From 6470d8af309b9253888068a6f3335429b47aa831 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 10:36:07 +0100 Subject: [PATCH 01/47] init spline subscriber Signed-off-by: Wojciech Czerski --- .../Include/SplineTools/SplineToolsTypeIds.h | 2 + .../Code/Source/Clients/SplinePublisher.cpp | 122 ++++++++++++++++++ .../Code/Source/Clients/SplinePublisher.h | 50 +++++++ .../Source/SplineToolsModuleInterface.cpp | 6 +- .../Code/splinetools_private_files.cmake | 2 + 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp create mode 100644 Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h diff --git a/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h b/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h index 3a8eac19..859712e8 100644 --- a/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h +++ b/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h @@ -22,4 +22,6 @@ namespace SplineTools inline constexpr const char* SplineSubscriberComponentTypeId = "{89B8A92A-8F17-4C30-AE0D-6B088C133283}"; inline constexpr const char* SplineSubscriberConfigTypeId = "{44317FD2-51A1-41CA-BA44-F8BCAE9757CE}"; + inline constexpr const char* SplinePublisherComponentTypeId = "{29c02686-04f6-416d-8f47-d2456a3e114c}"; + inline constexpr const char* SplinePublisherConfigTypeId = "{dc7ac312-0f47-4ef2-a1b7-02e8716cf4ee}"; } // namespace SplineTools diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp new file mode 100644 index 00000000..3573582e --- /dev/null +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -0,0 +1,122 @@ +#include "SplinePublisher.h" + +#include "ROS2/Utilities/ROS2Names.h" + +#include +#include + +namespace SplineTools +{ + SplinePublisherConfiguration::SplinePublisherConfiguration() + { + m_TopicConfig.m_type = "nav_msgs::msg::Path"; + m_TopicConfig.m_topic = "spline_path"; + } + + void SplinePublisherConfiguration::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("m_topicName", &SplinePublisherConfiguration::m_TopicConfig); + if (auto editContext = serializeContext->GetEditContext()) + { + editContext + ->Class( + "SplinePublisherConfiguration", "Configuration for the SplineSubscriber component") + ->ClassElement(AZ::Edit::ClassElements::Group, "SplineSubscriber Configuration") + ->DataElement(AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config"); + } + } + } + + void SplinePublisher::Reflect(AZ::ReflectContext* context) + { + SplinePublisherConfiguration::Reflect(context); + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(0)->Field("m_config", &SplinePublisher::m_config); + if (auto editContext = serializeContext->GetEditContext()) + { + editContext->Class("SplinePathPublisher", "Enables to publish spline as a ros2 path.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "SplinePathPublisher") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SplinePublisher::m_config, + "Configuration", + "Configuration for the SplinePathPublisher component"); + } + } + } + + SplinePublisher::SplinePublisher(const SplinePublisherConfiguration& config) + : m_config(config) + { + } + + void SplinePublisher::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC("SplineService", 0x2b674d3c)); + required.push_back(AZ_CRC_CE("ROS2Frame")); + } + + void SplinePublisher::Activate() + { + auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); + if (ros2Node) + { + m_publisher = ros2Node->create_publisher( + m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); + + AZ::TickBus::Handler::BusConnect(); + } + } + + void SplinePublisher::Deactivate() + { + AZ::TickBus::Handler::BusDisconnect(); + m_publisher.reset(); + } + + void SplinePublisher::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + AZ_UNUSED(deltaTime); + AZ_UNUSED(time); + + PublishSplineAsPath(); + } + + void SplinePublisher::PublishSplineAsPath() const + { + if (!m_publisher) + { + return; + } + + auto* ros2Frame = GetEntity()->FindComponent(); + nav_msgs::msg::Path pathMessage; + pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); // Set an appropriate frame ID (as per your use case) + pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); + + // Generate the path based on the spline (retrieve spline data from the SplineService) + AZStd::vector splinePoints; + LmbrCentral::SplineComponentRequestBus::EventResult( + splinePoints, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); + + for (const auto& point : splinePoints) + { + geometry_msgs::msg::PoseStamped poseStamped; + poseStamped.pose.position.x = point.GetX(); + poseStamped.pose.position.y = point.GetY(); + poseStamped.pose.position.z = point.GetZ(); + pathMessage.poses.push_back(poseStamped); + } + + // Publish the message + m_publisher->publish(pathMessage); + } +} // namespace SplineTools \ No newline at end of file diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h new file mode 100644 index 00000000..a8e4b533 --- /dev/null +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace SplineTools +{ + struct SplinePublisherConfiguration + { + SplinePublisherConfiguration(); + + AZ_TYPE_INFO(SplinePublisherConfiguration, SplinePublisherConfigTypeId); + static void Reflect(AZ::ReflectContext* context); + ROS2::TopicConfiguration m_TopicConfig{ rclcpp::ServicesQoS() }; + }; + + class SplinePublisher : public AZ::Component, public AZ::TickBus::Handler + { + public: + AZ_COMPONENT(SplinePublisher, SplinePublisherComponentTypeId); + + static void Reflect(AZ::ReflectContext* context); + + SplinePublisher() = default; + ~SplinePublisher() override = default; + explicit SplinePublisher(const SplinePublisherConfiguration& config); + + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + + // AZ::Component interface implementation + void Activate() override; + void Deactivate() override; + + // AZ::TickBus::Handler interface implementation + void OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) override; + + private: + void PublishSplineAsPath() const; + + SplinePublisherConfiguration m_config; + rclcpp::Publisher::SharedPtr m_publisher; + }; +} // namespace SplineTools \ No newline at end of file diff --git a/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp b/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp index 00f1b85d..22d55152 100644 --- a/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp +++ b/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp @@ -1,9 +1,11 @@ #include "SplineToolsModuleInterface.h" + #include #include +#include #include #include #include @@ -24,7 +26,9 @@ namespace SplineTools m_descriptors.end(), { SplineToolsSystemComponent::CreateDescriptor(), VisualizeSplineComponent::CreateDescriptor(), - SplineSubscriber::CreateDescriptor() }); + SplineSubscriber::CreateDescriptor(), + SplinePublisher::CreateDescriptor() + }); } AZ::ComponentTypeList SplineToolsModuleInterface::GetRequiredSystemComponents() const diff --git a/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake b/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake index 2c7ff46e..c90a9627 100644 --- a/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake +++ b/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake @@ -10,4 +10,6 @@ set(FILES Source/Clients/SplineSubscriber.cpp Source/Clients/SplineSubscriberConfig.h Source/Clients/SplineSubscriberConfig.cpp + Source/Clients/SplinePublisher.h + Source/Clients/SplinePublisher.cpp ) From 6ccf97ef5e87e378087dd98a34768171f5be32fc Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 10:46:55 +0100 Subject: [PATCH 02/47] clang format Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 17 ++++++++--------- .../Code/Source/Clients/SplinePublisher.h | 12 +++++++----- .../Code/Source/SplineToolsModuleInterface.cpp | 3 +-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 3573582e..151a73e0 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -17,16 +17,16 @@ namespace SplineTools { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() - ->Version(0) - ->Field("m_topicName", &SplinePublisherConfiguration::m_TopicConfig); + serializeContext->Class()->Version(0)->Field( + "m_topicName", &SplinePublisherConfiguration::m_TopicConfig); if (auto editContext = serializeContext->GetEditContext()) { editContext ->Class( "SplinePublisherConfiguration", "Configuration for the SplineSubscriber component") ->ClassElement(AZ::Edit::ClassElements::Group, "SplineSubscriber Configuration") - ->DataElement(AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config"); + ->DataElement( + AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config"); } } } @@ -69,8 +69,8 @@ namespace SplineTools auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); if (ros2Node) { - m_publisher = ros2Node->create_publisher( - m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); + m_publisher = + ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); AZ::TickBus::Handler::BusConnect(); } @@ -99,13 +99,12 @@ namespace SplineTools auto* ros2Frame = GetEntity()->FindComponent(); nav_msgs::msg::Path pathMessage; - pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); // Set an appropriate frame ID (as per your use case) + pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); // Set an appropriate frame ID (as per your use case) pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); // Generate the path based on the spline (retrieve spline data from the SplineService) AZStd::vector splinePoints; - LmbrCentral::SplineComponentRequestBus::EventResult( - splinePoints, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); + LmbrCentral::SplineComponentRequestBus::EventResult(splinePoints, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); for (const auto& point : splinePoints) { diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h index a8e4b533..4f69cf29 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h @@ -1,14 +1,14 @@ #pragma once -#include -#include #include #include #include #include +#include +#include -#include #include +#include namespace SplineTools { @@ -20,8 +20,10 @@ namespace SplineTools static void Reflect(AZ::ReflectContext* context); ROS2::TopicConfiguration m_TopicConfig{ rclcpp::ServicesQoS() }; }; - - class SplinePublisher : public AZ::Component, public AZ::TickBus::Handler + + class SplinePublisher + : public AZ::Component + , public AZ::TickBus::Handler { public: AZ_COMPONENT(SplinePublisher, SplinePublisherComponentTypeId); diff --git a/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp b/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp index 22d55152..58c07a6c 100644 --- a/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp +++ b/Gems/RobotecSplineTools/Code/Source/SplineToolsModuleInterface.cpp @@ -27,8 +27,7 @@ namespace SplineTools { SplineToolsSystemComponent::CreateDescriptor(), VisualizeSplineComponent::CreateDescriptor(), SplineSubscriber::CreateDescriptor(), - SplinePublisher::CreateDescriptor() - }); + SplinePublisher::CreateDescriptor() }); } AZ::ComponentTypeList SplineToolsModuleInterface::GetRequiredSystemComponents() const From 915d029c93eb68299a8f324a69da72989f4e9376 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 11:04:48 +0100 Subject: [PATCH 03/47] fix | get spline and convert into vector of vertex Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 151a73e0..e0054183 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -99,19 +99,30 @@ namespace SplineTools auto* ros2Frame = GetEntity()->FindComponent(); nav_msgs::msg::Path pathMessage; - pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); // Set an appropriate frame ID (as per your use case) + pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); - // Generate the path based on the spline (retrieve spline data from the SplineService) - AZStd::vector splinePoints; - LmbrCentral::SplineComponentRequestBus::EventResult(splinePoints, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); + // Retrieve spline data + AZStd::shared_ptr spline; + LmbrCentral::SplineComponentRequestBus::EventResult(spline, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); - for (const auto& point : splinePoints) + if (!spline) { + AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "Spline not found. Cannot generate spline path."); + return; + } + + // Retrieve vertices from the spline + const size_t vertexCount = spline->GetVertexCount(); + for (size_t i = 0; i < vertexCount; ++i) + { + const AZ::Vector3& vertex = spline->GetVertex(i); + + // Convert each vertex into a PoseStamped and add to the path geometry_msgs::msg::PoseStamped poseStamped; - poseStamped.pose.position.x = point.GetX(); - poseStamped.pose.position.y = point.GetY(); - poseStamped.pose.position.z = point.GetZ(); + poseStamped.pose.position.x = vertex.GetX(); + poseStamped.pose.position.y = vertex.GetY(); + poseStamped.pose.position.z = vertex.GetZ(); pathMessage.poses.push_back(poseStamped); } From 1b9affda505cdf4f231273253f9faa988b8dbea9 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 13:08:01 +0100 Subject: [PATCH 04/47] remove auto Signed-off-by: Wojciech Czerski --- .../RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index e0054183..c068536f 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -97,7 +97,8 @@ namespace SplineTools return; } - auto* ros2Frame = GetEntity()->FindComponent(); + const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); + nav_msgs::msg::Path pathMessage; pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); From 57322f8fba5610bf156a0b4a31a80a6d3863d234 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 15:21:03 +0100 Subject: [PATCH 05/47] apply review changes Signed-off-by: Wojciech Czerski --- .../Include/SplineTools/SplineToolsTypeIds.h | 4 +- .../Code/Source/Clients/SplinePublisher.cpp | 41 +++++++++++++++---- .../Code/Source/Clients/SplinePublisher.h | 4 +- .../Code/splinetools_private_files.cmake | 24 +++++------ 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h b/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h index 859712e8..a30a2aec 100644 --- a/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h +++ b/Gems/RobotecSplineTools/Code/Include/SplineTools/SplineToolsTypeIds.h @@ -22,6 +22,6 @@ namespace SplineTools inline constexpr const char* SplineSubscriberComponentTypeId = "{89B8A92A-8F17-4C30-AE0D-6B088C133283}"; inline constexpr const char* SplineSubscriberConfigTypeId = "{44317FD2-51A1-41CA-BA44-F8BCAE9757CE}"; - inline constexpr const char* SplinePublisherComponentTypeId = "{29c02686-04f6-416d-8f47-d2456a3e114c}"; - inline constexpr const char* SplinePublisherConfigTypeId = "{dc7ac312-0f47-4ef2-a1b7-02e8716cf4ee}"; + inline constexpr const char* SplinePublisherComponentTypeId = "{29C02686-04F6-416D-8F47-D2456A3E114C}"; + inline constexpr const char* SplinePublisherConfigTypeId = "{DC7AC312-0F47-4EF2-A1B7-02E8716CF4EE}"; } // namespace SplineTools diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index c068536f..5414853b 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -1,9 +1,8 @@ #include "SplinePublisher.h" -#include "ROS2/Utilities/ROS2Names.h" - #include #include +#include namespace SplineTools { @@ -60,20 +59,43 @@ namespace SplineTools void SplinePublisher::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("SplineService", 0x2b674d3c)); + required.push_back(AZ_CRC_CE("SplineService")); required.push_back(AZ_CRC_CE("ROS2Frame")); } void SplinePublisher::Activate() { + const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); + if (!ros2Frame) + { + AZ_Warning("SplinePublisher::Activate", false, "ROS2 Frame Component is not available!"); + return; + } + + AZStd::string frameNamespace = ros2Frame->GetNamespace(); + if (!frameNamespace.empty()) + { + m_config.m_TopicConfig.m_topic = AZStd::string::format("%s/%s", frameNamespace.c_str(), m_config.m_TopicConfig.m_topic.c_str()); + } + + // Create the ROS2 Publisher auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); if (ros2Node) { m_publisher = - ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); + ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.c_str(), m_config.m_TopicConfig.GetQoS()); AZ::TickBus::Handler::BusConnect(); } + + // const auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); + // if (ros2Node) + // { + // m_publisher = + // ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); + // + // AZ::TickBus::Handler::BusConnect(); + // } } void SplinePublisher::Deactivate() @@ -84,9 +106,6 @@ namespace SplineTools void SplinePublisher::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZ_UNUSED(deltaTime); - AZ_UNUSED(time); - PublishSplineAsPath(); } @@ -98,6 +117,11 @@ namespace SplineTools } const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); + if (!ros2Frame) + { + AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "ROS2 Frame Component is not available!"); + return; + } nav_msgs::msg::Path pathMessage; pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); @@ -127,7 +151,6 @@ namespace SplineTools pathMessage.poses.push_back(poseStamped); } - // Publish the message m_publisher->publish(pathMessage); } -} // namespace SplineTools \ No newline at end of file +} // namespace SplineTools diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h index 4f69cf29..40c4c574 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h @@ -41,7 +41,7 @@ namespace SplineTools void Deactivate() override; // AZ::TickBus::Handler interface implementation - void OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) override; + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; private: void PublishSplineAsPath() const; @@ -49,4 +49,4 @@ namespace SplineTools SplinePublisherConfiguration m_config; rclcpp::Publisher::SharedPtr m_publisher; }; -} // namespace SplineTools \ No newline at end of file +} // namespace SplineTools diff --git a/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake b/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake index c90a9627..a1260bfc 100644 --- a/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake +++ b/Gems/RobotecSplineTools/Code/splinetools_private_files.cmake @@ -1,15 +1,15 @@ set(FILES - Source/SplineToolsModuleInterface.cpp - Source/SplineToolsModuleInterface.h - Source/Clients/SplineToolsSystemComponent.cpp - Source/Clients/SplineToolsSystemComponent.h - Source/Clients/VisualizeSplineComponent.cpp - Source/Clients/VisualizeSplineComponent.h - Source/Clients/SplineSubscriber.h - Source/Clients/SplineSubscriber.cpp - Source/Clients/SplineSubscriberConfig.h - Source/Clients/SplineSubscriberConfig.cpp - Source/Clients/SplinePublisher.h - Source/Clients/SplinePublisher.cpp + Source/Clients/SplinePublisher.cpp + Source/Clients/SplinePublisher.h + Source/Clients/SplineSubscriber.cpp + Source/Clients/SplineSubscriber.h + Source/Clients/SplineSubscriberConfig.cpp + Source/Clients/SplineSubscriberConfig.h + Source/Clients/SplineToolsSystemComponent.cpp + Source/Clients/SplineToolsSystemComponent.h + Source/Clients/VisualizeSplineComponent.cpp + Source/Clients/VisualizeSplineComponent.h + Source/SplineToolsModuleInterface.cpp + Source/SplineToolsModuleInterface.h ) From ee5c5651b3c2c257abb15c2f5c7e95ec9da13f0c Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 15:23:54 +0100 Subject: [PATCH 06/47] remove comments Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 5414853b..6b6fc5b5 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -87,15 +87,6 @@ namespace SplineTools AZ::TickBus::Handler::BusConnect(); } - - // const auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); - // if (ros2Node) - // { - // m_publisher = - // ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.data(), m_config.m_TopicConfig.GetQoS()); - // - // AZ::TickBus::Handler::BusConnect(); - // } } void SplinePublisher::Deactivate() From 399c2d1fe678284826052b1d4c41a4a429184179 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 15:38:26 +0100 Subject: [PATCH 07/47] use emplace | format | apply reviews Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 6b6fc5b5..729c644e 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -134,12 +134,14 @@ namespace SplineTools { const AZ::Vector3& vertex = spline->GetVertex(i); - // Convert each vertex into a PoseStamped and add to the path - geometry_msgs::msg::PoseStamped poseStamped; + // Use emplace_back to construct PoseStamped in-place + pathMessage.poses.emplace_back(); + auto& poseStamped = pathMessage.poses.back(); + + // Set the pose values directly poseStamped.pose.position.x = vertex.GetX(); poseStamped.pose.position.y = vertex.GetY(); poseStamped.pose.position.z = vertex.GetZ(); - pathMessage.poses.push_back(poseStamped); } m_publisher->publish(pathMessage); From 5b7dd2609a10c6c3da196a6b320884ef0409cff4 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 12:13:12 +0100 Subject: [PATCH 08/47] change ros2 -> ROS 2 Signed-off-by: Wojciech Czerski --- Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 729c644e..380ff925 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -38,7 +38,7 @@ namespace SplineTools serializeContext->Class()->Version(0)->Field("m_config", &SplinePublisher::m_config); if (auto editContext = serializeContext->GetEditContext()) { - editContext->Class("SplinePathPublisher", "Enables to publish spline as a ros2 path.") + editContext->Class("SplinePathPublisher", "Enables to publish spline as a ROS 2 path.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "SplinePathPublisher") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") From 3fc175d343cb61adaf2e78ceb7796064909d1242 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 12:14:58 +0100 Subject: [PATCH 09/47] review resolved | topic changed to spline Signed-off-by: Wojciech Czerski --- Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 380ff925..47c1624d 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -9,7 +9,7 @@ namespace SplineTools SplinePublisherConfiguration::SplinePublisherConfiguration() { m_TopicConfig.m_type = "nav_msgs::msg::Path"; - m_TopicConfig.m_topic = "spline_path"; + m_TopicConfig.m_topic = "spline"; } void SplinePublisherConfiguration::Reflect(AZ::ReflectContext* context) From 9cf218ad7881daff156e60c621b34c0c042532a1 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 12:16:37 +0100 Subject: [PATCH 10/47] review resolved | use proper ROS 2 naming Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 47c1624d..514c8fd3 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -68,7 +68,7 @@ namespace SplineTools const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); if (!ros2Frame) { - AZ_Warning("SplinePublisher::Activate", false, "ROS2 Frame Component is not available!"); + AZ_Warning("SplinePublisher::Activate", false, "ROS 2 frame component is not available!"); return; } @@ -110,7 +110,7 @@ namespace SplineTools const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); if (!ros2Frame) { - AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "ROS2 Frame Component is not available!"); + AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "ROS 2 frame component is not available!"); return; } From 465135574f47e79764c6739efd69c6874f09c1a0 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 12:34:47 +0100 Subject: [PATCH 11/47] get ros2frame outside tick Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 25 +++++++++---------- .../Code/Source/Clients/SplinePublisher.h | 5 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index 514c8fd3..c4ecacc5 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -1,9 +1,10 @@ #include "SplinePublisher.h" -#include #include #include +#include + namespace SplineTools { SplinePublisherConfiguration::SplinePublisherConfiguration() @@ -52,8 +53,8 @@ namespace SplineTools } } - SplinePublisher::SplinePublisher(const SplinePublisherConfiguration& config) - : m_config(config) + SplinePublisher::SplinePublisher(SplinePublisherConfiguration config) + : m_config(std::move(config)) { } @@ -65,22 +66,21 @@ namespace SplineTools void SplinePublisher::Activate() { - const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); - if (!ros2Frame) + m_ros2FramePtr = GetEntity()->FindComponent(); + if (!m_ros2FramePtr) { AZ_Warning("SplinePublisher::Activate", false, "ROS 2 frame component is not available!"); return; } - AZStd::string frameNamespace = ros2Frame->GetNamespace(); - if (!frameNamespace.empty()) + if (!m_ros2FramePtr->GetNamespace().empty()) { - m_config.m_TopicConfig.m_topic = AZStd::string::format("%s/%s", frameNamespace.c_str(), m_config.m_TopicConfig.m_topic.c_str()); + m_config.m_TopicConfig.m_topic = + AZStd::string::format("%s/%s", m_ros2FramePtr->GetNamespace().c_str(), m_config.m_TopicConfig.m_topic.c_str()); } // Create the ROS2 Publisher - auto ros2Node = ROS2::ROS2Interface::Get()->GetNode(); - if (ros2Node) + if (const auto ros2Node = ROS2::ROS2Interface::Get()->GetNode()) { m_publisher = ros2Node->create_publisher(m_config.m_TopicConfig.m_topic.c_str(), m_config.m_TopicConfig.GetQoS()); @@ -107,15 +107,14 @@ namespace SplineTools return; } - const ROS2::ROS2FrameComponent* ros2Frame = GetEntity()->FindComponent(); - if (!ros2Frame) + if (!m_ros2FramePtr) { AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "ROS 2 frame component is not available!"); return; } nav_msgs::msg::Path pathMessage; - pathMessage.header.frame_id = ros2Frame->GetFrameID().data(); + pathMessage.header.frame_id = m_ros2FramePtr->GetFrameID().data(); pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); // Retrieve spline data diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h index 40c4c574..8ee8de06 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h @@ -5,8 +5,8 @@ #include #include #include +#include #include - #include #include @@ -32,7 +32,7 @@ namespace SplineTools SplinePublisher() = default; ~SplinePublisher() override = default; - explicit SplinePublisher(const SplinePublisherConfiguration& config); + explicit SplinePublisher(SplinePublisherConfiguration config); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); @@ -48,5 +48,6 @@ namespace SplineTools SplinePublisherConfiguration m_config; rclcpp::Publisher::SharedPtr m_publisher; + ROS2::ROS2FrameComponent* m_ros2FramePtr = nullptr; }; } // namespace SplineTools From 45bd34c6f204dc07b9a7e949ef85792adf9f5e4d Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:05:10 +0100 Subject: [PATCH 12/47] add update frequency Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 60 +++++++++++-------- .../Code/Source/Clients/SplinePublisher.h | 11 ++-- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index c4ecacc5..fc961e1e 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -2,31 +2,34 @@ #include #include - #include namespace SplineTools { - SplinePublisherConfiguration::SplinePublisherConfiguration() - { - m_TopicConfig.m_type = "nav_msgs::msg::Path"; - m_TopicConfig.m_topic = "spline"; - } - void SplinePublisherConfiguration::Reflect(AZ::ReflectContext* context) { - if (auto serializeContext = azrtti_cast(context)) + if (const auto serializeContext = azrtti_cast(context)) { - serializeContext->Class()->Version(0)->Field( - "m_topicName", &SplinePublisherConfiguration::m_TopicConfig); - if (auto editContext = serializeContext->GetEditContext()) + serializeContext->Class() + ->Version(0) + ->Field("m_topicName", &SplinePublisherConfiguration::m_TopicConfig) + ->Field("m_updateFrequency", &SplinePublisherConfiguration::m_updateFrequency); + + if (const auto editContext = serializeContext->GetEditContext()) { editContext ->Class( "SplinePublisherConfiguration", "Configuration for the SplineSubscriber component") ->ClassElement(AZ::Edit::ClassElements::Group, "SplineSubscriber Configuration") ->DataElement( - AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config"); + AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SplinePublisherConfiguration::m_updateFrequency, + "Update Frequency", + "How often path should be published.") + ->Attribute(AZ::Edit::Attributes::Min, 0.0) + ->Attribute(AZ::Edit::Attributes::Step, 1.0); } } } @@ -34,10 +37,11 @@ namespace SplineTools void SplinePublisher::Reflect(AZ::ReflectContext* context) { SplinePublisherConfiguration::Reflect(context); - if (auto serializeContext = azrtti_cast(context)) + if (const auto serializeContext = azrtti_cast(context)) { serializeContext->Class()->Version(0)->Field("m_config", &SplinePublisher::m_config); - if (auto editContext = serializeContext->GetEditContext()) + + if (const auto editContext = serializeContext->GetEditContext()) { editContext->Class("SplinePathPublisher", "Enables to publish spline as a ROS 2 path.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "SplinePathPublisher") @@ -53,6 +57,12 @@ namespace SplineTools } } + SplinePublisherConfiguration::SplinePublisherConfiguration() + { + m_TopicConfig.m_type = "nav_msgs::msg::Path"; + m_TopicConfig.m_topic = "spline"; + } + SplinePublisher::SplinePublisher(SplinePublisherConfiguration config) : m_config(std::move(config)) { @@ -73,6 +83,7 @@ namespace SplineTools return; } + // Format Ros Topic if (!m_ros2FramePtr->GetNamespace().empty()) { m_config.m_TopicConfig.m_topic = @@ -97,7 +108,11 @@ namespace SplineTools void SplinePublisher::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - PublishSplineAsPath(); + if (m_frameNumber++ == m_config.m_updateFrequency) + { + PublishSplineAsPath(); + m_frameNumber = 0; + } } void SplinePublisher::PublishSplineAsPath() const @@ -107,33 +122,30 @@ namespace SplineTools return; } - if (!m_ros2FramePtr) - { - AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "ROS 2 frame component is not available!"); - return; - } + AZ_Assert(m_ros2FramePtr, "ROS 2 frame component is not available!"); nav_msgs::msg::Path pathMessage; pathMessage.header.frame_id = m_ros2FramePtr->GetFrameID().data(); pathMessage.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp(); - // Retrieve spline data + // Get Spline AZStd::shared_ptr spline; LmbrCentral::SplineComponentRequestBus::EventResult(spline, GetEntityId(), &LmbrCentral::SplineComponentRequests::GetSpline); - if (!spline) { AZ_Warning("SplinePublisher::PublishSplineAsPath", false, "Spline not found. Cannot generate spline path."); return; } - // Retrieve vertices from the spline + // Get vertices from the spline const size_t vertexCount = spline->GetVertexCount(); + pathMessage.poses.reserve(vertexCount); // Reserve known size + for (size_t i = 0; i < vertexCount; ++i) { const AZ::Vector3& vertex = spline->GetVertex(i); - // Use emplace_back to construct PoseStamped in-place + // Use emplace_back to construct PoseStamped in place pathMessage.poses.emplace_back(); auto& poseStamped = pathMessage.poses.back(); diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h index 8ee8de06..9a2946c2 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.h @@ -14,16 +14,17 @@ namespace SplineTools { struct SplinePublisherConfiguration { - SplinePublisherConfiguration(); - AZ_TYPE_INFO(SplinePublisherConfiguration, SplinePublisherConfigTypeId); static void Reflect(AZ::ReflectContext* context); + ROS2::TopicConfiguration m_TopicConfig{ rclcpp::ServicesQoS() }; + int m_updateFrequency = 10; + SplinePublisherConfiguration(); }; - class SplinePublisher + class SplinePublisher final : public AZ::Component - , public AZ::TickBus::Handler + , protected AZ::TickBus::Handler { public: AZ_COMPONENT(SplinePublisher, SplinePublisherComponentTypeId); @@ -40,6 +41,7 @@ namespace SplineTools void Activate() override; void Deactivate() override; + protected: // AZ::TickBus::Handler interface implementation void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; @@ -47,6 +49,7 @@ namespace SplineTools void PublishSplineAsPath() const; SplinePublisherConfiguration m_config; + int m_frameNumber = 0; rclcpp::Publisher::SharedPtr m_publisher; ROS2::ROS2FrameComponent* m_ros2FramePtr = nullptr; }; From ffa7f34797fac19761f507a23145727e8e6d451a Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:17:19 +0100 Subject: [PATCH 13/47] add readme info | add update frequency Signed-off-by: Wojciech Czerski --- .../Code/Source/Clients/SplinePublisher.cpp | 8 ++++---- readme.md | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp index fc961e1e..226fd00a 100644 --- a/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp +++ b/Gems/RobotecSplineTools/Code/Source/Clients/SplinePublisher.cpp @@ -21,15 +21,15 @@ namespace SplineTools ->Class( "SplinePublisherConfiguration", "Configuration for the SplineSubscriber component") ->ClassElement(AZ::Edit::ClassElements::Group, "SplineSubscriber Configuration") - ->DataElement( - AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config") ->DataElement( AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_updateFrequency, "Update Frequency", - "How often path should be published.") + "How often path should be published (in ticks).") ->Attribute(AZ::Edit::Attributes::Min, 0.0) - ->Attribute(AZ::Edit::Attributes::Step, 1.0); + ->Attribute(AZ::Edit::Attributes::Step, 1.0) + ->DataElement( + AZ::Edit::UIHandlers::Default, &SplinePublisherConfiguration::m_TopicConfig, "Topic Config", "Topic Config"); } } } diff --git a/readme.md b/readme.md index 387456ee..54d7a942 100644 --- a/readme.md +++ b/readme.md @@ -10,8 +10,10 @@ Toolset for joystick-controlled cameras and spline animation tools. # SplineTools The tools for expanding the usability of the Spline component in O3DE. It allows to: - - Import spline from CSV file - - Export spline to a CSV file +- Publish spline points as a path with ROS 2 +- Import spline from CSV file +- Export spline to a CSV file + Having a CSV file formatted as : ```csv x,y,z @@ -32,6 +34,9 @@ Add SplineToolsEditorComponent next to the [Spline component](https://docs.o3de. If you switch `Local Coordinates` to true, the component will interpret coordinates as local to entity origin. ![](doc/SplineToolsEditorComponent.png) +To publish spline path, add `SplinePublisher` next to the [Spline component](https://docs.o3de.org/docs/user-guide/components/reference/shape/spline/). +Adjust **frequency update** to set how often the path will be published. + ## Using geo-referenced data The CSV file can contain the following columns: `lat`, `lon`, `alt` where every row contains the WGS-84 coordinate of the spline's node. From 23e9891e1f0ead66a44c089c1ce5eae3dff7cd0e Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:17:22 +0100 Subject: [PATCH 14/47] add readme info | add update frequency Signed-off-by: Wojciech Czerski --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 54d7a942..c597984d 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ If you switch `Local Coordinates` to true, the component will interpret coordina ![](doc/SplineToolsEditorComponent.png) To publish spline path, add `SplinePublisher` next to the [Spline component](https://docs.o3de.org/docs/user-guide/components/reference/shape/spline/). -Adjust **frequency update** to set how often the path will be published. +Adjust **update frequency** to set how often the path will be published. ## Using geo-referenced data From 7049997bd5c2c212102c7674c9a9d48c2247d03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pe=C5=82ka?= Date: Mon, 30 Jun 2025 12:22:59 +0200 Subject: [PATCH 15/47] Adjust Pointcloud, ImGuiProvider, ImGuizmo code to 2505 version of o3de. (#118) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adjust code to 2505 version of o3de. Co-authored-by: moudgils <47460854+moudgils@users.noreply.github.com> Signed-off-by: Michał Pełka * Make clang happy Signed-off-by: Michał Pełka * make ImGuiProvider work with 25050 (#121) Signed-off-by: Mateusz Żak * Adjust ImGuizmo Gem to compile with 2505 Signed-off-by: Michał Pełka --------- Signed-off-by: Michał Pełka Signed-off-by: Mateusz Żak Co-authored-by: moudgils <47460854+moudgils@users.noreply.github.com> Co-authored-by: Mateusz Żak --- Gems/ImGuiProvider/Code/CMakeLists.txt | 6 +-- .../Clients/ImGuiProviderSystemComponent.cpp | 25 ++++++----- Gems/ImGuizmo/Code/CMakeLists.txt | 2 +- .../Shaders/Pointclouds/Pointclouds.azsl | 4 +- Gems/Pointcloud/Code/CMakeLists.txt | 3 -- .../Render/PointcloudFeatureProcessor.cpp | 30 +++++++++---- .../Render/PointcloudFeatureProcessor.h | 3 +- .../PointcloudComponentController.cpp | 42 ++++++++++--------- Gems/Pointcloud/gem.json | 6 +-- 9 files changed, 68 insertions(+), 53 deletions(-) diff --git a/Gems/ImGuiProvider/Code/CMakeLists.txt b/Gems/ImGuiProvider/Code/CMakeLists.txt index 73fc8e7e..08945df6 100644 --- a/Gems/ImGuiProvider/Code/CMakeLists.txt +++ b/Gems/ImGuiProvider/Code/CMakeLists.txt @@ -30,7 +30,7 @@ ly_add_target( BUILD_DEPENDENCIES INTERFACE AZ::AzCore - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) # The ${gem_name}.Private.Object target is an internal target @@ -51,7 +51,7 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) @@ -138,7 +138,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC AZ::AzToolsFramework ${gem_name}.Private.Object - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public ) ly_add_target( diff --git a/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp b/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp index 10f635af..f6eea723 100644 --- a/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp +++ b/Gems/ImGuiProvider/Code/Source/Clients/ImGuiProviderSystemComponent.cpp @@ -12,8 +12,6 @@ #include #include #include -#include - #include #include #include @@ -125,18 +123,19 @@ namespace ImGuiProvider // if current context is not available through Imgui system bus, get context from pass and push is to imgui system bus if (!m_currentImGuiContext) { - AZ::Render::ImGuiPass* pass; - AZ::Render::ImGuiSystemRequestBus::BroadcastResult(pass, &AZ::Render::ImGuiSystemRequests::GetDefaultImGuiPass); - if (pass) + bool success; + AZ::Render::ImGuiSystemRequestBus::BroadcastResult( + success, &AZ::Render::ImGuiSystemRequests::PushActiveContextFromDefaultPass); + if (success) { - auto context = pass->GetContext(); - if (context) - { - AZ_Info("ImGuiProviderSystemComponent", "Gathering pass context and pushing as active"); - m_currentImGuiContext = context; - m_previousImGuiContext = context; - ImGui::SetCurrentContext(context); - } + AZ::Render::ImGuiSystemRequestBus::BroadcastResult( + m_currentImGuiContext, &AZ::Render::ImGuiSystemRequests::GetActiveContext); + m_previousImGuiContext = m_currentImGuiContext; + } + else + { + AZ_Error("ImGuiProviderSystemComponent::OnTick", false, "Failed to get active context from ImGuiSystemBus"); + return; } } // if needed move viewport icons diff --git a/Gems/ImGuizmo/Code/CMakeLists.txt b/Gems/ImGuizmo/Code/CMakeLists.txt index 1ba8071f..8b6ab5a7 100644 --- a/Gems/ImGuizmo/Code/CMakeLists.txt +++ b/Gems/ImGuizmo/Code/CMakeLists.txt @@ -52,7 +52,7 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework - Gem::Atom_Feature_Common.Static + Gem::Atom_Feature_Common.Public Gem::ImGui.Static ) diff --git a/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl b/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl index 844a6d60..7c0d6b9e 100644 --- a/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl +++ b/Gems/Pointcloud/Assets/Shaders/Pointclouds/Pointclouds.azsl @@ -8,8 +8,8 @@ #include #include -#include -#include +#include +#include ShaderResourceGroup PerDrawSrg : SRG_PerDraw { diff --git a/Gems/Pointcloud/Code/CMakeLists.txt b/Gems/Pointcloud/Code/CMakeLists.txt index 92d88c28..c288f08b 100644 --- a/Gems/Pointcloud/Code/CMakeLists.txt +++ b/Gems/Pointcloud/Code/CMakeLists.txt @@ -39,7 +39,6 @@ ly_add_target( Gem::Atom_RPI.Public Gem::Atom_Feature_Common Gem::Atom_Feature_Common.Public - Gem::Atom_Feature_Common.Static ) # The ${gem_name}.Private.Object target is an internal target @@ -64,7 +63,6 @@ ly_add_target( Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Feature_Common - Gem::AtomLyIntegration_CommonFeatures.Static ) # Here add ${gem_name} target, it depends on the Private Object library and Public API interface @@ -140,7 +138,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework $ Gem::Atom_Utils.Static - Gem::Atom_Feature_Common.Static Gem::AtomLyIntegration_CommonFeatures.Static PRIVATE AZ::AssetBuilderSDK diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp index e06a42c0..f6c37178 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.cpp @@ -99,7 +99,7 @@ namespace Pointcloud else { AZ::RPI::CommonBufferDescriptor desc; - desc.m_poolType = AZ::RPI::CommonBufferPoolType::ReadWrite; + desc.m_poolType = AZ::RPI::CommonBufferPoolType::DynamicInputAssembly; desc.m_bufferName = AZStd::string::format("PointcloudFeatureProcessor, %d", pcData.m_index); desc.m_byteCount = bufferSize; desc.m_elementSize = elementSize; @@ -158,7 +158,12 @@ namespace Pointcloud if (m_meshPipelineState && pcData.m_drawSrg && pcData.m_meshStreamBufferViews.front().GetByteCount() != 0) { pcData.m_drawPacket = BuildDrawPacket( - pcData.m_drawSrg, m_meshPipelineState, m_drawListTag, pcData.m_meshStreamBufferViews, pcData.m_vertices); + pcData.m_drawSrg, + m_meshPipelineState, + m_drawListTag, + pcData.m_meshStreamBufferViews, + pcData.m_geometryView, + pcData.m_vertices); } } } @@ -236,23 +241,33 @@ namespace Pointcloud const AZ::RPI::Ptr& pipelineState, const AZ::RHI::DrawListTag& drawListTag, const AZStd::span& streamBufferViews, + AZ::RHI::GeometryView& geometryView, uint32_t vertexCount) { + geometryView.Reset(); AZ::RHI::DrawLinear drawLinear; drawLinear.m_vertexCount = vertexCount; drawLinear.m_vertexOffset = 0; - drawLinear.m_instanceCount = 1; - drawLinear.m_instanceOffset = 0; + AZ::RHI::DrawInstanceArguments drawInstanceArgs; + drawInstanceArgs.m_instanceCount = 1; + drawInstanceArgs.m_instanceOffset = 0; + geometryView.SetDrawArguments(drawLinear); - AZ::RHI::DrawPacketBuilder drawPacketBuilder; + for (size_t i = 0; i < streamBufferViews.size(); ++i) + { + geometryView.AddStreamBufferView(streamBufferViews[i]); + } + AZ::RHI::DrawPacketBuilder drawPacketBuilder{ AZ::RHI::MultiDevice::AllDevices }; drawPacketBuilder.Begin(nullptr); - drawPacketBuilder.SetDrawArguments(drawLinear); + drawPacketBuilder.SetGeometryView(&geometryView); + drawPacketBuilder.SetDrawInstanceArguments(drawInstanceArgs); drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup()); AZ::RHI::DrawPacketBuilder::DrawRequest drawRequest; drawRequest.m_listTag = drawListTag; drawRequest.m_pipelineState = pipelineState->GetRHIPipelineState(); - drawRequest.m_streamBufferViews = streamBufferViews; + drawRequest.m_streamIndices = geometryView.GetFullStreamBufferIndices(); + drawPacketBuilder.AddDrawItem(drawRequest); return drawPacketBuilder.End(); } @@ -367,6 +382,7 @@ namespace Pointcloud } return AZStd::nullopt; } + void PointcloudFeatureProcessor::ConnectChangeEventHandler( const PointcloudHandle& pointcloudHandle, PointcloudChangedEvent::Handler& handler) { diff --git a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h index 5387ee25..59f1b9a0 100644 --- a/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h +++ b/Gems/Pointcloud/Code/Source/Render/PointcloudFeatureProcessor.h @@ -62,7 +62,7 @@ namespace Pointcloud PointcloudHandle m_index = 0; AZ::Data::Asset m_cloudVertexBufferAsset; AZ::Data::Instance m_cloudVertexBuffer = nullptr; - + AZ::RHI::GeometryView m_geometryView; AZStd::array m_meshStreamBufferViews; AZStd::vector m_pointData; uint32_t m_vertices = 0; @@ -92,6 +92,7 @@ namespace Pointcloud const AZ::RPI::Ptr& pipelineState, const AZ::RHI::DrawListTag& drawListTag, const AZStd::span& streamBufferViews, + AZ::RHI::GeometryView& geometryView, uint32_t vertexCount); AZ::RPI::Ptr m_meshPipelineState; diff --git a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp index 3fe621ae..7914dbe2 100644 --- a/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp +++ b/Gems/Pointcloud/Code/Source/Tools/Components/PointcloudComponentController.cpp @@ -96,27 +96,24 @@ namespace Pointcloud AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - if (auto serializeContext = azrtti_cast(context)) + serializeContext->Class()->Version(1)->Field( + "Configuration", &PointcloudComponentController::m_config); + + AZ::EditContext* editContext = serializeContext->GetEditContext(); + if (editContext) { - serializeContext->Class()->Version(1)->Field( - "Configuration", &PointcloudComponentController::m_config); + editContext->Class("PointcloudComponentController", "PointcloudComponentController") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "PointcloudComponentController") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - AZ::EditContext* editContext = serializeContext->GetEditContext(); - if (editContext) - { - editContext->Class("PointcloudComponentController", "PointcloudComponentController") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "PointcloudComponentController") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->Attribute(AZ::Edit::Attributes::Category, "RobotecTools") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - - ->DataElement( - AZ::Edit::UIHandlers::Default, - &PointcloudComponentController::m_config, - "Configuration", - "Configuration of the pointcloud") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &PointcloudComponentController::OnAssetChanged); - } + ->DataElement( + AZ::Edit::UIHandlers::Default, + &PointcloudComponentController::m_config, + "Configuration", + "Configuration of the pointcloud") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &PointcloudComponentController::OnAssetChanged); } } } @@ -138,13 +135,18 @@ namespace Pointcloud AZ_Assert(m_featureProcessor, "Failed to enable PointcloudFeatureProcessorInterface."); } } - m_featureProcessor->ConnectChangeEventHandler(m_config.m_pointcloudHandle, m_changeEventHandler); + + if (m_featureProcessor) + { + m_featureProcessor->ConnectChangeEventHandler(m_config.m_pointcloudHandle, m_changeEventHandler); + } OnAssetChanged(); }); } void PointcloudComponentController::Deactivate() { + m_changeEventHandler.Disconnect(); PointcloudConfigurationBus::Handler::BusDisconnect(); AZ::TransformNotificationBus::Handler::BusDisconnect(); if (m_featureProcessor) diff --git a/Gems/Pointcloud/gem.json b/Gems/Pointcloud/gem.json index ed62806c..8563bfb5 100644 --- a/Gems/Pointcloud/gem.json +++ b/Gems/Pointcloud/gem.json @@ -18,14 +18,14 @@ "" ], "icon_path": "preview.png", - "requirements": "Notice of any requirements for this Gem i.e. This requires X other gem", - "documentation_url": "Link to any documentation of your Gem", + "requirements": "", + "documentation_url": "", "dependencies": [ "Atom_RPI", "Atom" ], "repo_uri": "https://github.com/RobotecAI/robotec-o3de-tools", - "compatible_engines": ["o3de>=2.3.0"], + "compatible_engines": ["o3de>=4.2.0"], "engine_api_dependencies": [], "restricted": "Pointcloud" } From c91a03a39b48cdce39a76e1b104c94497bd67434 Mon Sep 17 00:00:00 2001 From: Patryk Antosz Date: Mon, 30 Jun 2025 12:23:13 +0200 Subject: [PATCH 16/47] Update GeoJSONSpawner to be compatible with O3DE 2505 (#124) Signed-off-by: Patryk Antosz --- .../Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp | 10 +++++----- Gems/GeoJSONSpawner/gem.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp b/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp index 9c855dae..9116fc1d 100644 --- a/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp +++ b/Gems/GeoJSONSpawner/Code/Source/GeoJSONSpawner/GeoJSONSpawnerUtils.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -314,7 +314,7 @@ namespace GeoJSONSpawner::GeoJSONUtils const AZStd::vector& featureObjects, const AZStd::unordered_map& spawnableAssetConfigurations) { - if (!ROS2::GeoreferenceRequestsBus::HasHandlers()) + if (!Georeferencing::GeoreferenceRequestsBus::HasHandlers()) { AZ_Error("GeoJSONSpawnerUtils", false, "Cannot convert WGS84 coordinates - Level is not geographically positioned."); return {}; @@ -336,14 +336,14 @@ namespace GeoJSONSpawner::GeoJSONUtils { constexpr float defaultScale = 1.0f; const AZ::Quaternion rotation = AZ::Quaternion::CreateIdentity(); - ROS2::WGS::WGS84Coordinate coordinate; + Georeferencing::WGS::WGS84Coordinate coordinate; AZ::Vector3 coordinateInLevel = AZ::Vector3(-1); coordinate.m_longitude = point[0]; coordinate.m_latitude = point[1]; coordinate.m_altitude = spawnableAssetConfig.m_raytraceStartingHeight; - ROS2::GeoreferenceRequestsBus::BroadcastResult( - coordinateInLevel, &ROS2::GeoreferenceRequestsBus::Events::ConvertFromWGS84ToLevel, coordinate); + Georeferencing::GeoreferenceRequestsBus::BroadcastResult( + coordinateInLevel, &Georeferencing::GeoreferenceRequestsBus::Events::ConvertFromWGS84ToLevel, coordinate); AZ::Transform transform{ coordinateInLevel, rotation, defaultScale }; spawnableEntityInfo.m_positions.emplace_back(AZStd::move(transform)); diff --git a/Gems/GeoJSONSpawner/gem.json b/Gems/GeoJSONSpawner/gem.json index 4e4dc340..edc9e747 100644 --- a/Gems/GeoJSONSpawner/gem.json +++ b/Gems/GeoJSONSpawner/gem.json @@ -18,10 +18,10 @@ "" ], "icon_path": "preview.png", - "requirements": "Requires ROS2 Gem", + "requirements": "Requires LevelGeoreferencing Gem", "documentation_url": "", "dependencies": [ - "ROS2" + "LevelGeoreferencing" ], "repo_uri": "", "compatible_engines": [], From f70295a8f570511381e00aa8c3d20a65a3b6361a Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 16:53:39 +0100 Subject: [PATCH 17/47] init | add notification bus interface class Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 45 +++++++++++++++++++ .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 13 +++++- .../Code/csvspawner_api_files.cmake | 1 + 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h new file mode 100644 index 00000000..d37ec19d --- /dev/null +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -0,0 +1,45 @@ +/** +* Copyright (C) Robotec AI - All Rights Reserved + * + * This source code is protected under international copyright law. All rights + * reserved and protected by the copyright holders. + * This file is confidential and only available to authorized individuals with + * the permission of the copyright holders. If you encounter this file and do + * not have permission, please contact the copyright holders and delete this + * file. + */ + +#pragma once + +#include +#include + +namespace CsvSpawner +{ + class CsvSpawnerInterface + : public AZ::EBusTraits + { + public: + virtual ~CsvSpawnerInterface() = default; + + virtual void OnEntitiesSpawnBegin( + const AZStd::vector& entitiesToSpawn, + const AZStd::unordered_map& spawnableAssetConfiguration, + const AZStd::string& physicsSceneName, + const AZ::EntityId& parentId) = 0; + + virtual void OnEntitiesSpawnFinished( + const AZStd::vector& entitiesToSpawn, + const AZStd::unordered_map& spawnableAssetConfiguration, + const AZStd::string& physicsSceneName, + const AZ::EntityId& parentId, + const AZStd::unordered_map& spawnTickets) = 0; + + // EBus Configuration - allow multiple listeners + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + }; + + // Create an EBus using the notification interface + using CsvSpawnerNotificationBus = AZ::EBus; + +} // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index b16b456c..deee76a1 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -11,14 +11,14 @@ #include "CsvSpawnerUtils.h" -#include "AzFramework/Physics/CollisionBus.h" +#include +#include #include #include #include #include -#include #include #include @@ -196,6 +196,10 @@ namespace CsvSpawner::CsvSpawnerUtils const AZStd::string& physicsSceneName, AZ::EntityId parentId) { + // Call CsvSpawner EBus notification + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, + entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId); + auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); const auto sceneHandle = sceneInterface->GetSceneHandle(physicsSceneName); @@ -289,6 +293,11 @@ namespace CsvSpawner::CsvSpawnerUtils spawner->SpawnAllEntities(ticket, optionalArgs); tickets[entityConfig.m_id] = AZStd::move(ticket); } + + // Call CsvSpawner EBus notification + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, + entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId, tickets); + return tickets; } diff --git a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake index c4fb100e..cd4cc9fe 100644 --- a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake @@ -1,4 +1,5 @@ set(FILES + Include/CsvSpawner/CsvSpawnerInterface.h Include/CsvSpawner/CsvSpawnerTypeIds.h ) From 537302451a32371c6a894ebda0f158fb5de6044f Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 17:03:14 +0100 Subject: [PATCH 18/47] clang format Signed-off-by: Wojciech Czerski --- .../Code/Include/CsvSpawner/CsvSpawnerInterface.h | 5 ++--- .../Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index d37ec19d..81ad30d4 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -1,5 +1,5 @@ /** -* Copyright (C) Robotec AI - All Rights Reserved + * Copyright (C) Robotec AI - All Rights Reserved * * This source code is protected under international copyright law. All rights * reserved and protected by the copyright holders. @@ -16,8 +16,7 @@ namespace CsvSpawner { - class CsvSpawnerInterface - : public AZ::EBusTraits + class CsvSpawnerInterface : public AZ::EBusTraits { public: virtual ~CsvSpawnerInterface() = default; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index deee76a1..fbee1ee7 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -197,8 +197,8 @@ namespace CsvSpawner::CsvSpawnerUtils AZ::EntityId parentId) { // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, - entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId); + CsvSpawnerNotificationBus::Broadcast( + &CsvSpawnerInterface::OnEntitiesSpawnBegin, entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId); auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); @@ -295,8 +295,13 @@ namespace CsvSpawner::CsvSpawnerUtils } // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, - entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId, tickets); + CsvSpawnerNotificationBus::Broadcast( + &CsvSpawnerInterface::OnEntitiesSpawnFinished, + entitiesToSpawn, + spawnableAssetConfiguration, + physicsSceneName, + parentId, + tickets); return tickets; } From 09e44bf4614ca1d7ffba73be5436345b8df3477c Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 17:34:03 +0100 Subject: [PATCH 19/47] remove not needed info in bus Signed-off-by: Wojciech Czerski --- .../Code/Include/CsvSpawner/CsvSpawnerInterface.h | 8 +------- .../Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 11 ++--------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 81ad30d4..e77e8532 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -21,15 +21,9 @@ namespace CsvSpawner public: virtual ~CsvSpawnerInterface() = default; - virtual void OnEntitiesSpawnBegin( - const AZStd::vector& entitiesToSpawn, - const AZStd::unordered_map& spawnableAssetConfiguration, - const AZStd::string& physicsSceneName, - const AZ::EntityId& parentId) = 0; + virtual void OnEntitiesSpawnBegin(const AZStd::string& physicsSceneName, const AZ::EntityId& parentId) = 0; virtual void OnEntitiesSpawnFinished( - const AZStd::vector& entitiesToSpawn, - const AZStd::unordered_map& spawnableAssetConfiguration, const AZStd::string& physicsSceneName, const AZ::EntityId& parentId, const AZStd::unordered_map& spawnTickets) = 0; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index fbee1ee7..6b89120e 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -197,8 +197,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ::EntityId parentId) { // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast( - &CsvSpawnerInterface::OnEntitiesSpawnBegin, entitiesToSpawn, spawnableAssetConfiguration, physicsSceneName, parentId); + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, physicsSceneName, parentId); auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); @@ -295,13 +294,7 @@ namespace CsvSpawner::CsvSpawnerUtils } // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast( - &CsvSpawnerInterface::OnEntitiesSpawnFinished, - entitiesToSpawn, - spawnableAssetConfiguration, - physicsSceneName, - parentId, - tickets); + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, physicsSceneName, parentId, tickets); return tickets; } From ee39e1cf98308365feee05241e5c5584b8dcf7ae Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 28 Jan 2025 17:46:26 +0100 Subject: [PATCH 20/47] remove bus info for spawn tickets Signed-off-by: Wojciech Czerski --- .../CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 5 +---- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index e77e8532..86cb68ad 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -23,10 +23,7 @@ namespace CsvSpawner virtual void OnEntitiesSpawnBegin(const AZStd::string& physicsSceneName, const AZ::EntityId& parentId) = 0; - virtual void OnEntitiesSpawnFinished( - const AZStd::string& physicsSceneName, - const AZ::EntityId& parentId, - const AZStd::unordered_map& spawnTickets) = 0; + virtual void OnEntitiesSpawnFinished(const AZStd::string& physicsSceneName, const AZ::EntityId& parentId) = 0; // EBus Configuration - allow multiple listeners static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 6b89120e..90d9ef2d 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -294,7 +294,7 @@ namespace CsvSpawner::CsvSpawnerUtils } // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, physicsSceneName, parentId, tickets); + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, physicsSceneName, parentId); return tickets; } From 2fbc8072ffd7726e90426d9ff31e55cc7b3ad4a3 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 10:50:16 +0100 Subject: [PATCH 21/47] move spawn utils to public include | spawn info bus struct Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 18 ++++++++++++++++++ .../CsvSpawner/CsvSpawnerUtils.h | 0 .../Source/CsvSpawner/CsvSpawnerComponent.h | 2 +- .../Source/CsvSpawner/CsvSpawnerCsvParser.cpp | 2 +- .../Source/CsvSpawner/CsvSpawnerCsvParser.h | 2 +- .../CsvSpawner/CsvSpawnerEditorComponent.cpp | 2 +- .../CsvSpawner/CsvSpawnerEditorComponent.h | 2 +- .../Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 2 +- .../CsvSpawner/Code/csvspawner_api_files.cmake | 1 + .../Code/csvspawner_private_files.cmake | 1 - 10 files changed, 25 insertions(+), 7 deletions(-) rename Gems/CsvSpawner/Code/{Source => Include}/CsvSpawner/CsvSpawnerUtils.h (100%) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 86cb68ad..1532bb7d 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -13,9 +13,27 @@ #include #include +#include namespace CsvSpawner { + + // Enum with success code for spawning + enum SpawnSuccessCode + { + Fail = -1, + Success = 0, + SpawnStopped = 1, + }; + + // Structure to hold spawn data + struct SpawnInfo + { + const AZStd::vector& m_EntitiesToSpawn; + const AZStd::string& m_PhysicsSceneName; + const AZ::EntityId& m_ParentId; + }; + class CsvSpawnerInterface : public AZ::EBusTraits { public: diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerUtils.h similarity index 100% rename from Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h rename to Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerUtils.h diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h index 9a86754b..72a533dd 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h @@ -10,7 +10,7 @@ #pragma once -#include "CsvSpawnerUtils.h" +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp index ffdb7997..55c108e1 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp @@ -8,12 +8,12 @@ * permission, please contact the copyright holders and delete this file. */ -#include "CsvSpawnerUtils.h" #include #include #include #include #include +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h index adf33746..0e0283c8 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h @@ -10,12 +10,12 @@ #pragma once -#include "CsvSpawnerUtils.h" #include #include #include #include #include +#include namespace CsvSpawner::CsvSpawnerUtils { diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp index d1a0932f..0aaf1353 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp @@ -12,7 +12,7 @@ #include "AzCore/Debug/Trace.h" #include "CsvSpawnerComponent.h" #include "CsvSpawnerCsvParser.h" -#include "CsvSpawnerUtils.h" +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h index c63e93a8..0e4b8bee 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h @@ -11,7 +11,7 @@ #pragma once #include "API/ToolsApplicationAPI.h" -#include "CsvSpawnerUtils.h" +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 90d9ef2d..3548eec2 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -9,7 +9,7 @@ * file. */ -#include "CsvSpawnerUtils.h" +#include #include #include diff --git a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake index cd4cc9fe..d0f6385b 100644 --- a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake @@ -2,4 +2,5 @@ set(FILES Include/CsvSpawner/CsvSpawnerInterface.h Include/CsvSpawner/CsvSpawnerTypeIds.h + Include/CsvSpawner/CsvSpawnerUtils.h ) diff --git a/Gems/CsvSpawner/Code/csvspawner_private_files.cmake b/Gems/CsvSpawner/Code/csvspawner_private_files.cmake index b59d4fce..a1c05509 100644 --- a/Gems/CsvSpawner/Code/csvspawner_private_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_private_files.cmake @@ -3,7 +3,6 @@ set(FILES Source/CsvSpawnerModuleInterface.cpp Source/CsvSpawnerModuleInterface.h Source/CsvSpawner/CsvSpawnerUtils.cpp - Source/CsvSpawner/CsvSpawnerUtils.h Source/CsvSpawner/CsvSpawnerComponent.cpp Source/CsvSpawner/CsvSpawnerComponent.h ) From 002c35b20b2787b72b352b1aaedaca18381e7822 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 11:47:05 +0100 Subject: [PATCH 22/47] add notify status code Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 21 +++++++------ .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 30 +++++++++++++++---- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 1532bb7d..832e2390 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -18,20 +18,23 @@ namespace CsvSpawner { - // Enum with success code for spawning - enum SpawnSuccessCode + // Enum with flags for spawning success code + enum SpawnStatusCode : uint8_t { - Fail = -1, Success = 0, - SpawnStopped = 1, + Fail = 1 << 0, + SpawnStopped = 1 << 1, + ErrorOccurred = 1 << 1, }; + AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatusCode); + // Structure to hold spawn data struct SpawnInfo { - const AZStd::vector& m_EntitiesToSpawn; - const AZStd::string& m_PhysicsSceneName; - const AZ::EntityId& m_ParentId; + const AZStd::vector& m_entitiesToSpawn; + const AZStd::string& m_physicsSceneName; + const AZ::EntityId& m_spawnerParentEntityId; }; class CsvSpawnerInterface : public AZ::EBusTraits @@ -39,9 +42,9 @@ namespace CsvSpawner public: virtual ~CsvSpawnerInterface() = default; - virtual void OnEntitiesSpawnBegin(const AZStd::string& physicsSceneName, const AZ::EntityId& parentId) = 0; + virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo) = 0; - virtual void OnEntitiesSpawnFinished(const AZStd::string& physicsSceneName, const AZ::EntityId& parentId) = 0; + virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_successCode) = 0; // EBus Configuration - allow multiple listeners static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 3548eec2..670f509f 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -196,8 +196,12 @@ namespace CsvSpawner::CsvSpawnerUtils const AZStd::string& physicsSceneName, AZ::EntityId parentId) { - // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, physicsSceneName, parentId); + SpawnInfo broadcastSpawnInfo = + SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. + SpawnStatusCode spawnStatusCode; // Spawn Status Code Status used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + + // Call CsvSpawner EBus notification - Begin + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); @@ -227,6 +231,9 @@ namespace CsvSpawner::CsvSpawnerUtils if (!spawnableAssetConfiguration.contains(entityConfig.m_name)) { AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); + + // Add notify code status + spawnStatusCode |= ErrorOccurred; continue; } @@ -256,6 +263,9 @@ namespace CsvSpawner::CsvSpawnerUtils } else { + // Add notify code status + spawnStatusCode |= ErrorOccurred; + continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. } @@ -265,10 +275,13 @@ namespace CsvSpawner::CsvSpawnerUtils AzFramework::EntitySpawnTicket ticket(spawnable); // Set the pre-spawn callback to set the name of the root entity to the name // of the spawnable - optionalArgs.m_preInsertionCallback = [transform](auto id, auto view) + optionalArgs.m_preInsertionCallback = [transform, &spawnStatusCode](auto id, auto view) { if (view.empty()) { + // Add notify code status + spawnStatusCode |= ErrorOccurred; + return; } AZ::Entity* root = *view.begin(); @@ -278,11 +291,14 @@ namespace CsvSpawner::CsvSpawnerUtils transformInterface->SetWorldTM(transform); }; optionalArgs.m_completionCallback = - [parentId]( + [parentId, &spawnStatusCode]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) { if (view.empty()) { + // Add notify code status + spawnStatusCode |= ErrorOccurred; + return; } const AZ::Entity* root = *view.begin(); @@ -293,8 +309,10 @@ namespace CsvSpawner::CsvSpawnerUtils tickets[entityConfig.m_id] = AZStd::move(ticket); } - // Call CsvSpawner EBus notification - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, physicsSceneName, parentId); + // Check is success spawn + tickets.empty() ? spawnStatusCode |= Fail : spawnStatusCode |= Success; + // Call CsvSpawner EBus notification - Finished + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); return tickets; } From 139bb38d450b886b378d751e76f90fe3573cf904 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 11:47:40 +0100 Subject: [PATCH 23/47] fix typo Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 832e2390..0eca2a51 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -24,7 +24,7 @@ namespace CsvSpawner Success = 0, Fail = 1 << 0, SpawnStopped = 1 << 1, - ErrorOccurred = 1 << 1, + ErrorOccurred = 1 << 2, }; AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatusCode); From 318d19fa485146345a130af72640f0526b0b9581 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 11:51:02 +0100 Subject: [PATCH 24/47] more context to enum spawn Signed-off-by: Wojciech Czerski --- .../Code/Include/CsvSpawner/CsvSpawnerInterface.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 0eca2a51..47b426a5 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -18,13 +18,13 @@ namespace CsvSpawner { - // Enum with flags for spawning success code - enum SpawnStatusCode : uint8_t + // Enum with flags for spawning status + enum class SpawnStatusCode : uint8_t { - Success = 0, - Fail = 1 << 0, - SpawnStopped = 1 << 1, - ErrorOccurred = 1 << 2, + Success = 0, // Operation succeeded. + Fail = 1 << 0, // Generic failure. + SpawnStopped = 1 << 1, // Spawning was stopped prematurely but not necessarily a failure. + ErrorOccurred = 1 << 2, // An error occurred during spawning (potentially recoverable). }; AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatusCode); From 0c456562f39550a6a1b15c1cc4d830e2b1f13b45 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 13:23:19 +0100 Subject: [PATCH 25/47] fix format | resolve errors Signed-off-by: Wojciech Czerski --- .../Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 670f509f..d7945534 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -233,7 +233,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); // Add notify code status - spawnStatusCode |= ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorOccurred; continue; } @@ -264,7 +264,7 @@ namespace CsvSpawner::CsvSpawnerUtils else { // Add notify code status - spawnStatusCode |= ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorOccurred; continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. @@ -280,7 +280,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorOccurred; return; } @@ -297,7 +297,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorOccurred; return; } @@ -310,7 +310,7 @@ namespace CsvSpawner::CsvSpawnerUtils } // Check is success spawn - tickets.empty() ? spawnStatusCode |= Fail : spawnStatusCode |= Success; + tickets.empty() ? spawnStatusCode |= SpawnStatusCode::Fail : spawnStatusCode |= SpawnStatusCode::Success; // Call CsvSpawner EBus notification - Finished CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); From bb29e4030e1924e3d497b4f6129f20ecda3bb3b0 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 13:27:27 +0100 Subject: [PATCH 26/47] rename member Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 47b426a5..e5d5bed6 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -44,7 +44,7 @@ namespace CsvSpawner virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo) = 0; - virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_successCode) = 0; + virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode) = 0; // EBus Configuration - allow multiple listeners static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; From 5a24a369e8fc09487a72a53d9a1173c858c3358c Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 13:42:03 +0100 Subject: [PATCH 27/47] add default override implentation | make override optional Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index e5d5bed6..39cb7c28 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -42,9 +42,9 @@ namespace CsvSpawner public: virtual ~CsvSpawnerInterface() = default; - virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo) = 0; + virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo){} - virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode) = 0; + virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode){} // EBus Configuration - allow multiple listeners static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; From 54e6f127090369f7406433a019274d6e219449e5 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 29 Jan 2025 13:53:34 +0100 Subject: [PATCH 28/47] add description Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 39cb7c28..1eb789bd 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -18,35 +18,65 @@ namespace CsvSpawner { - // Enum with flags for spawning status + /** + * @brief Flags representing the status of an CsvSpawner::Spawn() operation. + * + * SpawnStatusCode provides various status indicators for entity spawning. + * These flags help track whether spawning was successful, stopped, or failed. + */ enum class SpawnStatusCode : uint8_t { - Success = 0, // Operation succeeded. - Fail = 1 << 0, // Generic failure. - SpawnStopped = 1 << 1, // Spawning was stopped prematurely but not necessarily a failure. - ErrorOccurred = 1 << 2, // An error occurred during spawning (potentially recoverable). + Success = 0, ///< Operation succeeded. + Fail = 1 << 0, ///< Generic failure. + SpawnStopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. + ErrorOccurred = 1 << 2, ///< An error occurred during spawning (potentially recoverable). }; + /// Enable bitwise operations for SpawnStatusCode. AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatusCode); - // Structure to hold spawn data + /** + * @brief Structure holding data related to CsvSpawner entity spawning. + * + * SpawnInfo contains information about the entities to be spawned, the physics scene + * they belong to, and the parent entity responsible for the spawn operation. + */ struct SpawnInfo { - const AZStd::vector& m_entitiesToSpawn; - const AZStd::string& m_physicsSceneName; - const AZ::EntityId& m_spawnerParentEntityId; + const AZStd::vector& m_entitiesToSpawn; ///< List of entities to spawn. + const AZStd::string& m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. + const AZ::EntityId& m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. }; + /** + * @brief Interface for handling entity spawn events for Csv Spawner. + * + * CsvSpawnerInterface is an Event Bus interface that notifies multiple + * listeners when entity spawning begins and finishes. + */ class CsvSpawnerInterface : public AZ::EBusTraits { public: virtual ~CsvSpawnerInterface() = default; - virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo){} + /** + * @brief Called when entity spawning begins. + * @param m_spawnInfo Struct holding information about entities to be spawned. + */ + virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo) + { + } - virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode){} + /** + * @brief Called when entity spawning finishes. + * @param m_spawnInfo Struct holding information about entities to be spawned. + * @param m_statusCode Status code indicating success, failure and warnings of the spawn. + */ + virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode) + { + } - // EBus Configuration - allow multiple listeners + /// EBus Configuration - Allows multiple listeners to handle events. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; }; From 22c36280841217a540fee51fec27ceabd71874d7 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:30:26 +0100 Subject: [PATCH 29/47] undo make public utils Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp | 8301 +++++++++-------- .../Include/CsvSpawner/CsvSpawnerInterface.h | 3 +- .../Source/CsvSpawner/CsvSpawnerComponent.h | 1 + .../Source/CsvSpawner/CsvSpawnerCsvParser.cpp | 1 - .../Source/CsvSpawner/CsvSpawnerCsvParser.h | 4 - .../CsvSpawner/CsvSpawnerEditorComponent.cpp | 2 +- .../CsvSpawner/CsvSpawnerEditorComponent.h | 4 +- .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 2 +- .../CsvSpawner/CsvSpawnerUtils.h | 0 .../Code/csvspawner_api_files.cmake | 1 - .../Code/csvspawner_private_files.cmake | 1 + 11 files changed, 4362 insertions(+), 3958 deletions(-) rename Gems/CsvSpawner/Code/{Include => Source}/CsvSpawner/CsvSpawnerUtils.h (100%) diff --git a/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp b/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp index 9cebfc2b..e55f2c24 100644 --- a/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp +++ b/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp @@ -33,16 +33,15 @@ SOFTWARE. * @brief Defines functionality needed for basic CSV parsing */ - #include #include #include #include #include #include -#include #include #include +#include #include /* Copyright 2017 https://github.com/mandreyel @@ -93,545 +92,591 @@ SOFTWARE. #define MIO_PAGE_HEADER #ifdef _WIN32 -# include +#include #else -# include +#include #endif -namespace mio { - -/** - * This is used by `basic_mmap` to determine whether to create a read-only or - * a read-write memory mapping. - */ -enum class access_mode +namespace mio { - read, - write -}; -/** - * Determines the operating system's page allocation granularity. - * - * On the first call to this function, it invokes the operating system specific syscall - * to determine the page size, caches the value, and returns it. Any subsequent call to - * this function serves the cached value, so no further syscalls are made. - */ -inline size_t page_size() -{ - static const size_t page_size = [] + /** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ + enum class access_mode + { + read, + write + }; + + /** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ + inline size_t page_size() { + static const size_t page_size = [] + { #ifdef _WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - return SystemInfo.dwAllocationGranularity; + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; #else - return sysconf(_SC_PAGE_SIZE); + return sysconf(_SC_PAGE_SIZE); #endif - }(); - return page_size; -} + }(); + return page_size; + } -/** - * Alligns `offset` to the operating's system page size such that it subtracts the - * difference until the nearest page boundary before `offset`, or does nothing if - * `offset` is already page aligned. - */ -inline size_t make_offset_page_aligned(size_t offset) noexcept -{ - const size_t page_size_ = page_size(); - // Use integer division to round down to the nearest page alignment. - return offset / page_size_ * page_size_; -} + /** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ + inline size_t make_offset_page_aligned(size_t offset) noexcept + { + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; + } } // namespace mio #endif // MIO_PAGE_HEADER - +#include #include #include #include -#include #ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif // WIN32_LEAN_AND_MEAN -# include +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include #else // ifdef _WIN32 -# define INVALID_HANDLE_VALUE -1 +#define INVALID_HANDLE_VALUE -1 #endif // ifdef _WIN32 -namespace mio { +namespace mio +{ -// This value may be provided as the `length` parameter to the constructor or -// `map`, in which case a memory mapping of the entire file is created. -enum { map_entire_file = 0 }; + // This value may be provided as the `length` parameter to the constructor or + // `map`, in which case a memory mapping of the entire file is created. + enum + { + map_entire_file = 0 + }; #ifdef _WIN32 -using file_handle_type = HANDLE; + using file_handle_type = HANDLE; #else -using file_handle_type = int; + using file_handle_type = int; #endif -// This value represents an invalid file handle type. This can be used to -// determine whether `basic_mmap::file_handle` is valid, for example. -const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; + // This value represents an invalid file handle type. This can be used to + // determine whether `basic_mmap::file_handle` is valid, for example. + const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; -template -struct basic_mmap -{ - using value_type = ByteT; - using size_type = size_t; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using difference_type = std::ptrdiff_t; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using iterator_category = std::random_access_iterator_tag; - using handle_type = file_handle_type; - - static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); - -private: - // Points to the first requested byte, and not to the actual start of the mapping. - pointer data_ = nullptr; - - // Length--in bytes--requested by user (which may not be the length of the - // full mapping) and the length of the full mapping. - size_type length_ = 0; - size_type mapped_length_ = 0; - - // Letting user map a file using both an existing file handle and a path - // introcudes some complexity (see `is_handle_internal_`). - // On POSIX, we only need a file handle to create a mapping, while on - // Windows systems the file handle is necessary to retrieve a file mapping - // handle, but any subsequent operations on the mapped region must be done - // through the latter. - handle_type file_handle_ = INVALID_HANDLE_VALUE; + template + struct basic_mmap + { + using value_type = ByteT; + using size_type = size_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using difference_type = std::ptrdiff_t; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using iterator_category = std::random_access_iterator_tag; + using handle_type = file_handle_type; + + static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); + + private: + // Points to the first requested byte, and not to the actual start of the mapping. + pointer data_ = nullptr; + + // Length--in bytes--requested by user (which may not be the length of the + // full mapping) and the length of the full mapping. + size_type length_ = 0; + size_type mapped_length_ = 0; + + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity (see `is_handle_internal_`). + // On POSIX, we only need a file handle to create a mapping, while on + // Windows systems the file handle is necessary to retrieve a file mapping + // handle, but any subsequent operations on the mapped region must be done + // through the latter. + handle_type file_handle_ = INVALID_HANDLE_VALUE; #ifdef _WIN32 - handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; + handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; #endif - // Letting user map a file using both an existing file handle and a path - // introcudes some complexity in that we must not close the file handle if - // user provided it, but we must close it if we obtained it using the - // provided path. For this reason, this flag is used to determine when to - // close `file_handle_`. - bool is_handle_internal_; + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity in that we must not close the file handle if + // user provided it, but we must close it if we obtained it using the + // provided path. For this reason, this flag is used to determine when to + // close `file_handle_`. + bool is_handle_internal_; -public: - /** - * The default constructed mmap object is in a non-mapped state, that is, - * any operation that attempts to access nonexistent underlying data will - * result in undefined behaviour/segmentation faults. - */ - basic_mmap() = default; + public: + /** + * The default constructed mmap object is in a non-mapped state, that is, + * any operation that attempts to access nonexistent underlying data will + * result in undefined behaviour/segmentation faults. + */ + basic_mmap() = default; #ifdef __cpp_exceptions - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - template - basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(path, offset, length, error); - if(error) { throw std::system_error(error); } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template + basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(path, offset, length, error); + if (error) + { + throw std::system_error(error); + } + } - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(handle, offset, length, error); - if(error) { throw std::system_error(error); } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(handle, offset, length, error); + if (error) + { + throw std::system_error(error); + } + } #endif // __cpp_exceptions - /** - * `basic_mmap` has single-ownership semantics, so transferring ownership - * may only be accomplished by moving the object. - */ - basic_mmap(const basic_mmap&) = delete; - basic_mmap(basic_mmap&&); - basic_mmap& operator=(const basic_mmap&) = delete; - basic_mmap& operator=(basic_mmap&&); + /** + * `basic_mmap` has single-ownership semantics, so transferring ownership + * may only be accomplished by moving the object. + */ + basic_mmap(const basic_mmap&) = delete; + basic_mmap(basic_mmap&&); + basic_mmap& operator=(const basic_mmap&) = delete; + basic_mmap& operator=(basic_mmap&&); - /** - * If this is a read-write mapping, the destructor invokes sync. Regardless - * of the access mode, unmap is invoked as a final step. - */ - ~basic_mmap(); + /** + * If this is a read-write mapping, the destructor invokes sync. Regardless + * of the access mode, unmap is invoked as a final step. + */ + ~basic_mmap(); - /** - * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, - * however, a mapped region of a file gets its own handle, which is returned by - * 'mapping_handle'. - */ - handle_type file_handle() const noexcept { return file_handle_; } - handle_type mapping_handle() const noexcept; + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept + { + return file_handle_; + } + handle_type mapping_handle() const noexcept; - /** Returns whether a valid memory mapping has been created. */ - bool is_open() const noexcept { return file_handle_ != invalid_handle; } + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept + { + return file_handle_ != invalid_handle; + } - /** - * Returns true if no mapping was established, that is, conceptually the - * same as though the length that was mapped was 0. This function is - * provided so that this class has Container semantics. - */ - bool empty() const noexcept { return length() == 0; } + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept + { + return length() == 0; + } - /** Returns true if a mapping was established. */ - bool is_mapped() const noexcept; + /** Returns true if a mapping was established. */ + bool is_mapped() const noexcept; - /** - * `size` and `length` both return the logical length, i.e. the number of bytes - * user requested to be mapped, while `mapped_length` returns the actual number of - * bytes that were mapped which is a multiple of the underlying operating system's - * page allocation granularity. - */ - size_type size() const noexcept { return length(); } - size_type length() const noexcept { return length_; } - size_type mapped_length() const noexcept { return mapped_length_; } + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept + { + return length(); + } + size_type length() const noexcept + { + return length_; + } + size_type mapped_length() const noexcept + { + return mapped_length_; + } - /** Returns the offset relative to the start of the mapping. */ - size_type mapping_offset() const noexcept - { - return mapped_length_ - length_; - } + /** Returns the offset relative to the start of the mapping. */ + size_type mapping_offset() const noexcept + { + return mapped_length_ - length_; + } - /** - * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping - * exists. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > pointer data() noexcept { return data_; } - const_pointer data() const noexcept { return data_; } + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template::type> + pointer data() noexcept + { + return data_; + } + const_pointer data() const noexcept + { + return data_; + } - /** - * Returns an iterator to the first requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > iterator begin() noexcept { return data(); } - const_iterator begin() const noexcept { return data(); } - const_iterator cbegin() const noexcept { return data(); } + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template::type> + iterator begin() noexcept + { + return data(); + } + const_iterator begin() const noexcept + { + return data(); + } + const_iterator cbegin() const noexcept + { + return data(); + } - /** - * Returns an iterator one past the last requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > iterator end() noexcept { return data() + length(); } - const_iterator end() const noexcept { return data() + length(); } - const_iterator cend() const noexcept { return data() + length(); } + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template::type> + iterator end() noexcept + { + return data() + length(); + } + const_iterator end() const noexcept + { + return data() + length(); + } + const_iterator cend() const noexcept + { + return data() + length(); + } - /** - * Returns a reverse iterator to the last memory mapped byte, if a valid - * memory mapping exists, otherwise this function call is undefined - * behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const noexcept - { return const_reverse_iterator(end()); } - const_reverse_iterator crbegin() const noexcept - { return const_reverse_iterator(end()); } + /** + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. + */ + template::type> + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + + /** + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. + */ + template::type> + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } + + /** + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. + */ + reference operator[](const size_type i) noexcept + { + return data_[i]; + } + const_reference operator[](const size_type i) const noexcept + { + return data_[i]; + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template + void map(const String& path, const size_type offset, const size_type length, std::error_code& error); + + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. + */ + template + void map(const String& path, std::error_code& error) + { + map(path, 0, map_entire_file, error); + } + + /** + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error); + + /** + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code& error) + { + map(handle, 0, map_entire_file, error); + } + + /** + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. + * + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. + */ + void unmap(); + + void swap(basic_mmap& other); + + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template + typename std::enable_if::type sync(std::error_code& error); + + /** + * All operators compare the address of the first byte and size of the two mapped + * regions. + */ + + private: + template::type> + pointer get_mapping_start() noexcept + { + return !data() ? nullptr : data() - mapping_offset(); + } + + const_pointer get_mapping_start() const noexcept + { + return !data() ? nullptr : data() - mapping_offset(); + } + + /** + * The destructor syncs changes to disk if `AccessMode` is `write`, but not + * if it's `read`, but since the destructor cannot be templated, we need to + * do SFINAE in a dedicated function, where one syncs and the other is a noop. + */ + template + typename std::enable_if::type conditional_sync(); + template + typename std::enable_if::type conditional_sync(); + }; + + template + bool operator==(const basic_mmap& a, const basic_mmap& b); + + template + bool operator!=(const basic_mmap& a, const basic_mmap& b); + + template + bool operator<(const basic_mmap& a, const basic_mmap& b); + + template + bool operator<=(const basic_mmap& a, const basic_mmap& b); + + template + bool operator>(const basic_mmap& a, const basic_mmap& b); + + template + bool operator>=(const basic_mmap& a, const basic_mmap& b); /** - * Returns a reverse iterator past the first mapped byte, if a valid memory - * mapping exists, otherwise this function call is undefined behaviour. + * This is the basis for all read-only mmap objects and should be preferred over + * directly using `basic_mmap`. */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - const_reverse_iterator rend() const noexcept - { return const_reverse_iterator(begin()); } - const_reverse_iterator crend() const noexcept - { return const_reverse_iterator(begin()); } + template + using basic_mmap_source = basic_mmap; /** - * Returns a reference to the `i`th byte from the first requested byte (as returned - * by `data`). If this is invoked when no valid memory mapping has been created - * prior to this call, undefined behaviour ensues. + * This is the basis for all read-write mmap objects and should be preferred over + * directly using `basic_mmap`. */ - reference operator[](const size_type i) noexcept { return data_[i]; } - const_reference operator[](const size_type i) const noexcept { return data_[i]; } + template + using basic_mmap_sink = basic_mmap; /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). */ - template - void map(const String& path, const size_type offset, - const size_type length, std::error_code& error); + using mmap_source = basic_mmap_source; + using ummap_source = basic_mmap_source; + + using mmap_sink = basic_mmap_sink; + using ummap_sink = basic_mmap_sink; /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * The entire file is mapped. + * Convenience factory method that constructs a mapping for any `basic_mmap` or + * `basic_mmap` type. */ - template - void map(const String& path, std::error_code& error) + template + MMap make_mmap(const MappingToken& token, int64_t offset, int64_t length, std::error_code& error) { - map(path, 0, map_entire_file, error); + MMap mmap; + mmap.map(token, offset, length, error); + return mmap; } /** - * Establishes a memory mapping with AccessMode. If the mapping is - * unsuccesful, the reason is reported via `error` and the object remains in - * a state as if this function hadn't been called. + * Convenience factory method. * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector`, or similar), or a + * `mmap_source::handle_type`. */ - void map(const handle_type handle, const size_type offset, - const size_type length, std::error_code& error); + template + mmap_source make_mmap_source( + const MappingToken& token, mmap_source::size_type offset, mmap_source::size_type length, std::error_code& error) + { + return make_mmap(token, offset, length, error); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is - * unsuccesful, the reason is reported via `error` and the object remains in - * a state as if this function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * The entire file is mapped. - */ - void map(const handle_type handle, std::error_code& error) + template + mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) { - map(handle, 0, map_entire_file, error); + return make_mmap_source(token, 0, map_entire_file, error); } /** - * If a valid memory mapping has been created prior to this call, this call - * instructs the kernel to unmap the memory region and disassociate this object - * from the file. + * Convenience factory method. * - * The file handle associated with the file that is mapped is only closed if the - * mapping was created using a file path. If, on the other hand, an existing - * file handle was used to create the mapping, the file handle is not closed. - */ - void unmap(); - - void swap(basic_mmap& other); - - /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ - template - typename std::enable_if::type - sync(std::error_code& error); - - /** - * All operators compare the address of the first byte and size of the two mapped - * regions. + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector`, or similar), or a + * `mmap_sink::handle_type`. */ - -private: - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > pointer get_mapping_start() noexcept + template + mmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset, mmap_sink::size_type length, std::error_code& error) { - return !data() ? nullptr : data() - mapping_offset(); + return make_mmap(token, offset, length, error); } - const_pointer get_mapping_start() const noexcept + template + mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) { - return !data() ? nullptr : data() - mapping_offset(); + return make_mmap_sink(token, 0, map_entire_file, error); } - /** - * The destructor syncs changes to disk if `AccessMode` is `write`, but not - * if it's `read`, but since the destructor cannot be templated, we need to - * do SFINAE in a dedicated function, where one syncs and the other is a noop. - */ - template - typename std::enable_if::type - conditional_sync(); - template - typename std::enable_if::type conditional_sync(); -}; - -template -bool operator==(const basic_mmap& a, - const basic_mmap& b); - -template -bool operator!=(const basic_mmap& a, - const basic_mmap& b); - -template -bool operator<(const basic_mmap& a, - const basic_mmap& b); - -template -bool operator<=(const basic_mmap& a, - const basic_mmap& b); - -template -bool operator>(const basic_mmap& a, - const basic_mmap& b); - -template -bool operator>=(const basic_mmap& a, - const basic_mmap& b); - -/** - * This is the basis for all read-only mmap objects and should be preferred over - * directly using `basic_mmap`. - */ -template -using basic_mmap_source = basic_mmap; +} // namespace mio -/** - * This is the basis for all read-write mmap objects and should be preferred over - * directly using `basic_mmap`. - */ -template -using basic_mmap_sink = basic_mmap; - -/** - * These aliases cover the most common use cases, both representing a raw byte stream - * (either with a char or an unsigned char/uint8_t). - */ -using mmap_source = basic_mmap_source; -using ummap_source = basic_mmap_source; - -using mmap_sink = basic_mmap_sink; -using ummap_sink = basic_mmap_sink; - -/** - * Convenience factory method that constructs a mapping for any `basic_mmap` or - * `basic_mmap` type. - */ -template< - typename MMap, - typename MappingToken -> MMap make_mmap(const MappingToken& token, - int64_t offset, int64_t length, std::error_code& error) -{ - MMap mmap; - mmap.map(token, offset, length, error); - return mmap; -} - -/** - * Convenience factory method. - * - * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, - * `std::filesystem::path`, `std::vector`, or similar), or a - * `mmap_source::handle_type`. - */ -template -mmap_source make_mmap_source(const MappingToken& token, mmap_source::size_type offset, - mmap_source::size_type length, std::error_code& error) -{ - return make_mmap(token, offset, length, error); -} - -template -mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) -{ - return make_mmap_source(token, 0, map_entire_file, error); -} - -/** - * Convenience factory method. - * - * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, - * `std::filesystem::path`, `std::vector`, or similar), or a - * `mmap_sink::handle_type`. - */ -template -mmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset, - mmap_sink::size_type length, std::error_code& error) -{ - return make_mmap(token, offset, length, error); -} - -template -mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) -{ - return make_mmap_sink(token, 0, map_entire_file, error); -} - -} // namespace mio - -// #include "detail/mmap.ipp" -/* Copyright 2017 https://github.com/mandreyel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the "Software"), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// #include "detail/mmap.ipp" +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MIO_BASIC_MMAP_IMPL @@ -667,648 +712,639 @@ mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) #include -namespace mio { -namespace detail { +namespace mio +{ + namespace detail + { -template< - typename S, - typename C = typename std::decay::type, - typename = decltype(std::declval().data()), - typename = typename std::enable_if< - std::is_same::value + template< + typename S, + typename C = typename std::decay::type, + typename = decltype(std::declval().data()), + typename = typename std::enable_if< + std::is_same::value #ifdef _WIN32 - || std::is_same::value -#endif - >::type -> struct char_type_helper { - using type = typename C::value_type; -}; - -template -struct char_type { - using type = typename char_type_helper::type; -}; - -// TODO: can we avoid this brute force approach? -template<> -struct char_type { - using type = char; -}; - -template<> -struct char_type { - using type = char; -}; - -template -struct char_type { - using type = char; -}; - -template -struct char_type { - using type = char; -}; + || std::is_same::value +#endif + >::type> + struct char_type_helper + { + using type = typename C::value_type; + }; + + template + struct char_type + { + using type = typename char_type_helper::type; + }; + + // TODO: can we avoid this brute force approach? + template<> + struct char_type + { + using type = char; + }; + + template<> + struct char_type + { + using type = char; + }; + + template + struct char_type + { + using type = char; + }; + + template + struct char_type + { + using type = char; + }; #ifdef _WIN32 -template<> -struct char_type { - using type = wchar_t; -}; - -template<> -struct char_type { - using type = wchar_t; -}; - -template -struct char_type { - using type = wchar_t; -}; - -template -struct char_type { - using type = wchar_t; -}; + template<> + struct char_type + { + using type = wchar_t; + }; + + template<> + struct char_type + { + using type = wchar_t; + }; + + template + struct char_type + { + using type = wchar_t; + }; + + template + struct char_type + { + using type = wchar_t; + }; #endif // _WIN32 -template -struct is_c_str_helper -{ - static constexpr bool value = std::is_same< - CharT*, - // TODO: I'm so sorry for this... Can this be made cleaner? - typename std::add_pointer< - typename std::remove_cv< - typename std::remove_pointer< - typename std::decay< - S - >::type - >::type - >::type - >::type - >::value; -}; - -template -struct is_c_str -{ - static constexpr bool value = is_c_str_helper::value; -}; + template + struct is_c_str_helper + { + static constexpr bool value = std::is_same< + CharT*, + // TODO: I'm so sorry for this... Can this be made cleaner? + typename std::add_pointer< + typename std::remove_cv::type>::type>::type>::type>::value; + }; + + template + struct is_c_str + { + static constexpr bool value = is_c_str_helper::value; + }; #ifdef _WIN32 -template -struct is_c_wstr -{ - static constexpr bool value = is_c_str_helper::value; -}; + template + struct is_c_wstr + { + static constexpr bool value = is_c_str_helper::value; + }; #endif // _WIN32 -template -struct is_c_str_or_c_wstr -{ - static constexpr bool value = is_c_str::value + template + struct is_c_str_or_c_wstr + { + static constexpr bool value = is_c_str::value #ifdef _WIN32 - || is_c_wstr::value + || is_c_wstr::value #endif - ; -}; + ; + }; -template< - typename String, - typename = decltype(std::declval().data()), - typename = typename std::enable_if::value>::type -> const typename char_type::type* c_str(const String& path) -{ - return path.data(); -} + template< + typename String, + typename = decltype(std::declval().data()), + typename = typename std::enable_if::value>::type> + const typename char_type::type* c_str(const String& path) + { + return path.data(); + } -template< - typename String, - typename = decltype(std::declval().empty()), - typename = typename std::enable_if::value>::type -> bool empty(const String& path) -{ - return path.empty(); -} + template< + typename String, + typename = decltype(std::declval().empty()), + typename = typename std::enable_if::value>::type> + bool empty(const String& path) + { + return path.empty(); + } -template< - typename String, - typename = typename std::enable_if::value>::type -> const typename char_type::type* c_str(String path) -{ - return path; -} + template::value>::type> + const typename char_type::type* c_str(String path) + { + return path; + } -template< - typename String, - typename = typename std::enable_if::value>::type -> bool empty(String path) -{ - return !path || (*path == 0); -} + template::value>::type> + bool empty(String path) + { + return !path || (*path == 0); + } -} // namespace detail + } // namespace detail } // namespace mio #endif // MIO_STRING_UTIL_HEADER - #include #ifndef _WIN32 -# include -# include -# include -# include +#include +#include +#include +#include #endif -namespace mio { -namespace detail { +namespace mio +{ + namespace detail + { #ifdef _WIN32 -namespace win { + namespace win + { -/** Returns the 4 upper bytes of an 8-byte integer. */ -inline DWORD int64_high(int64_t n) noexcept -{ - return n >> 32; -} + /** Returns the 4 upper bytes of an 8-byte integer. */ + inline DWORD int64_high(int64_t n) noexcept + { + return n >> 32; + } -/** Returns the 4 lower bytes of an 8-byte integer. */ -inline DWORD int64_low(int64_t n) noexcept -{ - return n & 0xffffffff; -} + /** Returns the 4 lower bytes of an 8-byte integer. */ + inline DWORD int64_low(int64_t n) noexcept + { + return n & 0xffffffff; + } -template< - typename String, - typename = typename std::enable_if< - std::is_same::type, char>::value - >::type -> file_handle_type open_file_helper(const String& path, const access_mode mode) -{ - return ::CreateFileA(c_str(path), - mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); -} + template::type, char>::value>::type> + file_handle_type open_file_helper(const String& path, const access_mode mode) + { + return ::CreateFileA( + c_str(path), + mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + } -template -typename std::enable_if< - std::is_same::type, wchar_t>::value, - file_handle_type ->::type open_file_helper(const String& path, const access_mode mode) -{ - return ::CreateFileW(c_str(path), - mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); -} + template + typename std::enable_if::type, wchar_t>::value, file_handle_type>::type + open_file_helper(const String& path, const access_mode mode) + { + return ::CreateFileW( + c_str(path), + mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + } -} // win + } // namespace win #endif // _WIN32 -/** - * Returns the last platform specific system error (errno on POSIX and - * GetLastError on Win) as a `std::error_code`. - */ -inline std::error_code last_error() noexcept -{ - std::error_code error; + /** + * Returns the last platform specific system error (errno on POSIX and + * GetLastError on Win) as a `std::error_code`. + */ + inline std::error_code last_error() noexcept + { + std::error_code error; #ifdef _WIN32 - error.assign(GetLastError(), std::system_category()); + error.assign(GetLastError(), std::system_category()); #else - error.assign(errno, std::system_category()); + error.assign(errno, std::system_category()); #endif - return error; -} + return error; + } -template -file_handle_type open_file(const String& path, const access_mode mode, - std::error_code& error) -{ - error.clear(); - if(detail::empty(path)) - { - error = std::make_error_code(std::errc::invalid_argument); - return invalid_handle; - } + template + file_handle_type open_file(const String& path, const access_mode mode, std::error_code& error) + { + error.clear(); + if (detail::empty(path)) + { + error = std::make_error_code(std::errc::invalid_argument); + return invalid_handle; + } #ifdef _WIN32 - const auto handle = win::open_file_helper(path, mode); + const auto handle = win::open_file_helper(path, mode); #else // POSIX - const auto handle = ::open(c_str(path), - mode == access_mode::read ? O_RDONLY : O_RDWR); + const auto handle = ::open(c_str(path), mode == access_mode::read ? O_RDONLY : O_RDWR); #endif - if(handle == invalid_handle) - { - error = detail::last_error(); - } - return handle; -} + if (handle == invalid_handle) + { + error = detail::last_error(); + } + return handle; + } -inline size_t query_file_size(file_handle_type handle, std::error_code& error) -{ - error.clear(); + inline size_t query_file_size(file_handle_type handle, std::error_code& error) + { + error.clear(); #ifdef _WIN32 - LARGE_INTEGER file_size; - if(::GetFileSizeEx(handle, &file_size) == 0) - { - error = detail::last_error(); - return 0; - } - return static_cast(file_size.QuadPart); + LARGE_INTEGER file_size; + if (::GetFileSizeEx(handle, &file_size) == 0) + { + error = detail::last_error(); + return 0; + } + return static_cast(file_size.QuadPart); #else // POSIX - struct stat sbuf; - if(::fstat(handle, &sbuf) == -1) - { - error = detail::last_error(); - return 0; - } - return sbuf.st_size; + struct stat sbuf; + if (::fstat(handle, &sbuf) == -1) + { + error = detail::last_error(); + return 0; + } + return sbuf.st_size; #endif -} + } -struct mmap_context -{ - char* data; - int64_t length; - int64_t mapped_length; + struct mmap_context + { + char* data; + int64_t length; + int64_t mapped_length; #ifdef _WIN32 - file_handle_type file_mapping_handle; + file_handle_type file_mapping_handle; #endif -}; + }; -inline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset, - const int64_t length, const access_mode mode, std::error_code& error) -{ - const int64_t aligned_offset = make_offset_page_aligned(offset); - const int64_t length_to_map = offset - aligned_offset + length; + inline mmap_context memory_map( + const file_handle_type file_handle, const int64_t offset, const int64_t length, const access_mode mode, std::error_code& error) + { + const int64_t aligned_offset = make_offset_page_aligned(offset); + const int64_t length_to_map = offset - aligned_offset + length; #ifdef _WIN32 - const int64_t max_file_size = offset + length; - const auto file_mapping_handle = ::CreateFileMapping( - file_handle, - 0, - mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, - win::int64_high(max_file_size), - win::int64_low(max_file_size), - 0); - if(file_mapping_handle == invalid_handle) - { - error = detail::last_error(); - return {}; - } - char* mapping_start = static_cast(::MapViewOfFile( - file_mapping_handle, - mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, - win::int64_high(aligned_offset), - win::int64_low(aligned_offset), - length_to_map)); - if(mapping_start == nullptr) - { - // Close file handle if mapping it failed. - ::CloseHandle(file_mapping_handle); - error = detail::last_error(); - return {}; - } + const int64_t max_file_size = offset + length; + const auto file_mapping_handle = ::CreateFileMapping( + file_handle, + 0, + mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, + win::int64_high(max_file_size), + win::int64_low(max_file_size), + 0); + if (file_mapping_handle == invalid_handle) + { + error = detail::last_error(); + return {}; + } + char* mapping_start = static_cast(::MapViewOfFile( + file_mapping_handle, + mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, + win::int64_high(aligned_offset), + win::int64_low(aligned_offset), + length_to_map)); + if (mapping_start == nullptr) + { + // Close file handle if mapping it failed. + ::CloseHandle(file_mapping_handle); + error = detail::last_error(); + return {}; + } #else // POSIX - char* mapping_start = static_cast(::mmap( - 0, // Don't give hint as to where to map. - length_to_map, - mode == access_mode::read ? PROT_READ : PROT_WRITE, - MAP_SHARED, - file_handle, - aligned_offset)); - if(mapping_start == MAP_FAILED) - { - error = detail::last_error(); - return {}; - } + char* mapping_start = static_cast(::mmap( + 0, // Don't give hint as to where to map. + length_to_map, + mode == access_mode::read ? PROT_READ : PROT_WRITE, + MAP_SHARED, + file_handle, + aligned_offset)); + if (mapping_start == MAP_FAILED) + { + error = detail::last_error(); + return {}; + } #endif - mmap_context ctx; - ctx.data = mapping_start + offset - aligned_offset; - ctx.length = length; - ctx.mapped_length = length_to_map; + mmap_context ctx; + ctx.data = mapping_start + offset - aligned_offset; + ctx.length = length; + ctx.mapped_length = length_to_map; #ifdef _WIN32 - ctx.file_mapping_handle = file_mapping_handle; + ctx.file_mapping_handle = file_mapping_handle; #endif - return ctx; -} - -} // namespace detail - -// -- basic_mmap -- + return ctx; + } -template -basic_mmap::~basic_mmap() -{ - conditional_sync(); - unmap(); -} + } // namespace detail -template -basic_mmap::basic_mmap(basic_mmap&& other) - : data_(std::move(other.data_)) - , length_(std::move(other.length_)) - , mapped_length_(std::move(other.mapped_length_)) - , file_handle_(std::move(other.file_handle_)) -#ifdef _WIN32 - , file_mapping_handle_(std::move(other.file_mapping_handle_)) -#endif - , is_handle_internal_(std::move(other.is_handle_internal_)) -{ - other.data_ = nullptr; - other.length_ = other.mapped_length_ = 0; - other.file_handle_ = invalid_handle; -#ifdef _WIN32 - other.file_mapping_handle_ = invalid_handle; -#endif -} + // -- basic_mmap -- -template -basic_mmap& -basic_mmap::operator=(basic_mmap&& other) -{ - if(this != &other) + template + basic_mmap::~basic_mmap() { - // First the existing mapping needs to be removed. + conditional_sync(); unmap(); - data_ = std::move(other.data_); - length_ = std::move(other.length_); - mapped_length_ = std::move(other.mapped_length_); - file_handle_ = std::move(other.file_handle_); + } + + template + basic_mmap::basic_mmap(basic_mmap&& other) + : data_(std::move(other.data_)) + , length_(std::move(other.length_)) + , mapped_length_(std::move(other.mapped_length_)) + , file_handle_(std::move(other.file_handle_)) #ifdef _WIN32 - file_mapping_handle_ = std::move(other.file_mapping_handle_); + , file_mapping_handle_(std::move(other.file_mapping_handle_)) #endif - is_handle_internal_ = std::move(other.is_handle_internal_); - - // The moved from basic_mmap's fields need to be reset, because - // otherwise other's destructor will unmap the same mapping that was - // just moved into this. + , is_handle_internal_(std::move(other.is_handle_internal_)) + { other.data_ = nullptr; other.length_ = other.mapped_length_ = 0; other.file_handle_ = invalid_handle; #ifdef _WIN32 other.file_mapping_handle_ = invalid_handle; #endif - other.is_handle_internal_ = false; } - return *this; -} -template -typename basic_mmap::handle_type -basic_mmap::mapping_handle() const noexcept -{ + template + basic_mmap& basic_mmap::operator=(basic_mmap&& other) + { + if (this != &other) + { + // First the existing mapping needs to be removed. + unmap(); + data_ = std::move(other.data_); + length_ = std::move(other.length_); + mapped_length_ = std::move(other.mapped_length_); + file_handle_ = std::move(other.file_handle_); #ifdef _WIN32 - return file_mapping_handle_; -#else - return file_handle_; + file_mapping_handle_ = std::move(other.file_mapping_handle_); #endif -} + is_handle_internal_ = std::move(other.is_handle_internal_); -template -template -void basic_mmap::map(const String& path, const size_type offset, - const size_type length, std::error_code& error) -{ - error.clear(); - if(detail::empty(path)) - { - error = std::make_error_code(std::errc::invalid_argument); - return; - } - const auto handle = detail::open_file(path, AccessMode, error); - if(error) - { - return; + // The moved from basic_mmap's fields need to be reset, because + // otherwise other's destructor will unmap the same mapping that was + // just moved into this. + other.data_ = nullptr; + other.length_ = other.mapped_length_ = 0; + other.file_handle_ = invalid_handle; +#ifdef _WIN32 + other.file_mapping_handle_ = invalid_handle; +#endif + other.is_handle_internal_ = false; + } + return *this; } - map(handle, offset, length, error); - // This MUST be after the call to map, as that sets this to true. - if(!error) + template + typename basic_mmap::handle_type basic_mmap::mapping_handle() const noexcept { - is_handle_internal_ = true; +#ifdef _WIN32 + return file_mapping_handle_; +#else + return file_handle_; +#endif } -} -template -void basic_mmap::map(const handle_type handle, - const size_type offset, const size_type length, std::error_code& error) -{ - error.clear(); - if(handle == invalid_handle) + template + template + void basic_mmap::map(const String& path, const size_type offset, const size_type length, std::error_code& error) { - error = std::make_error_code(std::errc::bad_file_descriptor); - return; - } + error.clear(); + if (detail::empty(path)) + { + error = std::make_error_code(std::errc::invalid_argument); + return; + } + const auto handle = detail::open_file(path, AccessMode, error); + if (error) + { + return; + } - const auto file_size = detail::query_file_size(handle, error); - if(error) - { - return; + map(handle, offset, length, error); + // This MUST be after the call to map, as that sets this to true. + if (!error) + { + is_handle_internal_ = true; + } } - if(offset + length > file_size) + template + void basic_mmap::map( + const handle_type handle, const size_type offset, const size_type length, std::error_code& error) { - error = std::make_error_code(std::errc::invalid_argument); - return; - } + error.clear(); + if (handle == invalid_handle) + { + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } - const auto ctx = detail::memory_map(handle, offset, - length == map_entire_file ? (file_size - offset) : length, - AccessMode, error); - if(!error) - { - // We must unmap the previous mapping that may have existed prior to this call. - // Note that this must only be invoked after a new mapping has been created in - // order to provide the strong guarantee that, should the new mapping fail, the - // `map` function leaves this instance in a state as though the function had - // never been invoked. - unmap(); - file_handle_ = handle; - is_handle_internal_ = false; - data_ = reinterpret_cast(ctx.data); - length_ = ctx.length; - mapped_length_ = ctx.mapped_length; + const auto file_size = detail::query_file_size(handle, error); + if (error) + { + return; + } + + if (offset + length > file_size) + { + error = std::make_error_code(std::errc::invalid_argument); + return; + } + + const auto ctx = detail::memory_map(handle, offset, length == map_entire_file ? (file_size - offset) : length, AccessMode, error); + if (!error) + { + // We must unmap the previous mapping that may have existed prior to this call. + // Note that this must only be invoked after a new mapping has been created in + // order to provide the strong guarantee that, should the new mapping fail, the + // `map` function leaves this instance in a state as though the function had + // never been invoked. + unmap(); + file_handle_ = handle; + is_handle_internal_ = false; + data_ = reinterpret_cast(ctx.data); + length_ = ctx.length; + mapped_length_ = ctx.mapped_length; #ifdef _WIN32 - file_mapping_handle_ = ctx.file_mapping_handle; + file_mapping_handle_ = ctx.file_mapping_handle; #endif + } } -} -template -template -typename std::enable_if::type -basic_mmap::sync(std::error_code& error) -{ - error.clear(); - if(!is_open()) + template + template + typename std::enable_if::type basic_mmap::sync(std::error_code& error) { - error = std::make_error_code(std::errc::bad_file_descriptor); - return; - } + error.clear(); + if (!is_open()) + { + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } - if(data()) - { + if (data()) + { #ifdef _WIN32 - if(::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 - || ::FlushFileBuffers(file_handle_) == 0) + if (::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 || ::FlushFileBuffers(file_handle_) == 0) #else // POSIX - if(::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) + if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) #endif + { + error = detail::last_error(); + return; + } + } +#ifdef _WIN32 + if (::FlushFileBuffers(file_handle_) == 0) { error = detail::last_error(); - return; } - } -#ifdef _WIN32 - if(::FlushFileBuffers(file_handle_) == 0) - { - error = detail::last_error(); - } #endif -} + } -template -void basic_mmap::unmap() -{ - if(!is_open()) { return; } - // TODO do we care about errors here? -#ifdef _WIN32 - if(is_mapped()) + template + void basic_mmap::unmap() { - ::UnmapViewOfFile(get_mapping_start()); - ::CloseHandle(file_mapping_handle_); - } + if (!is_open()) + { + return; + } + // TODO do we care about errors here? +#ifdef _WIN32 + if (is_mapped()) + { + ::UnmapViewOfFile(get_mapping_start()); + ::CloseHandle(file_mapping_handle_); + } #else // POSIX - if(data_) { ::munmap(const_cast(get_mapping_start()), mapped_length_); } + if (data_) + { + ::munmap(const_cast(get_mapping_start()), mapped_length_); + } #endif - // If `file_handle_` was obtained by our opening it (when map is called with - // a path, rather than an existing file handle), we need to close it, - // otherwise it must not be closed as it may still be used outside this - // instance. - if(is_handle_internal_) - { + // If `file_handle_` was obtained by our opening it (when map is called with + // a path, rather than an existing file handle), we need to close it, + // otherwise it must not be closed as it may still be used outside this + // instance. + if (is_handle_internal_) + { #ifdef _WIN32 - ::CloseHandle(file_handle_); + ::CloseHandle(file_handle_); #else // POSIX - ::close(file_handle_); + ::close(file_handle_); #endif - } + } - // Reset fields to their default values. - data_ = nullptr; - length_ = mapped_length_ = 0; - file_handle_ = invalid_handle; + // Reset fields to their default values. + data_ = nullptr; + length_ = mapped_length_ = 0; + file_handle_ = invalid_handle; #ifdef _WIN32 - file_mapping_handle_ = invalid_handle; + file_mapping_handle_ = invalid_handle; #endif -} + } -template -bool basic_mmap::is_mapped() const noexcept -{ + template + bool basic_mmap::is_mapped() const noexcept + { #ifdef _WIN32 - return file_mapping_handle_ != invalid_handle; + return file_mapping_handle_ != invalid_handle; #else // POSIX - return is_open(); + return is_open(); #endif -} + } -template -void basic_mmap::swap(basic_mmap& other) -{ - if(this != &other) + template + void basic_mmap::swap(basic_mmap& other) { - using std::swap; - swap(data_, other.data_); - swap(file_handle_, other.file_handle_); + if (this != &other) + { + using std::swap; + swap(data_, other.data_); + swap(file_handle_, other.file_handle_); #ifdef _WIN32 - swap(file_mapping_handle_, other.file_mapping_handle_); + swap(file_mapping_handle_, other.file_mapping_handle_); #endif - swap(length_, other.length_); - swap(mapped_length_, other.mapped_length_); - swap(is_handle_internal_, other.is_handle_internal_); + swap(length_, other.length_); + swap(mapped_length_, other.mapped_length_); + swap(is_handle_internal_, other.is_handle_internal_); + } } -} -template -template -typename std::enable_if::type -basic_mmap::conditional_sync() -{ - // This is invoked from the destructor, so not much we can do about - // failures here. - std::error_code ec; - sync(ec); -} + template + template + typename std::enable_if::type basic_mmap::conditional_sync() + { + // This is invoked from the destructor, so not much we can do about + // failures here. + std::error_code ec; + sync(ec); + } -template -template -typename std::enable_if::type -basic_mmap::conditional_sync() -{ - // noop -} + template + template + typename std::enable_if::type basic_mmap::conditional_sync() + { + // noop + } -template -bool operator==(const basic_mmap& a, - const basic_mmap& b) -{ - return a.data() == b.data() - && a.size() == b.size(); -} + template + bool operator==(const basic_mmap& a, const basic_mmap& b) + { + return a.data() == b.data() && a.size() == b.size(); + } -template -bool operator!=(const basic_mmap& a, - const basic_mmap& b) -{ - return !(a == b); -} + template + bool operator!=(const basic_mmap& a, const basic_mmap& b) + { + return !(a == b); + } -template -bool operator<(const basic_mmap& a, - const basic_mmap& b) -{ - if(a.data() == b.data()) { return a.size() < b.size(); } - return a.data() < b.data(); -} + template + bool operator<(const basic_mmap& a, const basic_mmap& b) + { + if (a.data() == b.data()) + { + return a.size() < b.size(); + } + return a.data() < b.data(); + } -template -bool operator<=(const basic_mmap& a, - const basic_mmap& b) -{ - return !(a > b); -} + template + bool operator<=(const basic_mmap& a, const basic_mmap& b) + { + return !(a > b); + } -template -bool operator>(const basic_mmap& a, - const basic_mmap& b) -{ - if(a.data() == b.data()) { return a.size() > b.size(); } - return a.data() > b.data(); -} + template + bool operator>(const basic_mmap& a, const basic_mmap& b) + { + if (a.data() == b.data()) + { + return a.size() > b.size(); + } + return a.data() > b.data(); + } -template -bool operator>=(const basic_mmap& a, - const basic_mmap& b) -{ - return !(a < b); -} + template + bool operator>=(const basic_mmap& a, const basic_mmap& b) + { + return !(a < b); + } } // namespace mio #endif // MIO_BASIC_MMAP_IMPL - #endif // MIO_MMAP_HEADER /* Copyright 2017 https://github.com/mandreyel * @@ -1334,56 +1370,57 @@ bool operator>=(const basic_mmap& a, #define MIO_PAGE_HEADER #ifdef _WIN32 -# include +#include #else -# include +#include #endif -namespace mio { - -/** - * This is used by `basic_mmap` to determine whether to create a read-only or - * a read-write memory mapping. - */ -enum class access_mode +namespace mio { - read, - write -}; -/** - * Determines the operating system's page allocation granularity. - * - * On the first call to this function, it invokes the operating system specific syscall - * to determine the page size, caches the value, and returns it. Any subsequent call to - * this function serves the cached value, so no further syscalls are made. - */ -inline size_t page_size() -{ - static const size_t page_size = [] + /** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ + enum class access_mode + { + read, + write + }; + + /** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ + inline size_t page_size() { + static const size_t page_size = [] + { #ifdef _WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - return SystemInfo.dwAllocationGranularity; + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; #else - return sysconf(_SC_PAGE_SIZE); + return sysconf(_SC_PAGE_SIZE); #endif - }(); - return page_size; -} + }(); + return page_size; + } -/** - * Alligns `offset` to the operating's system page size such that it subtracts the - * difference until the nearest page boundary before `offset`, or does nothing if - * `offset` is already page aligned. - */ -inline size_t make_offset_page_aligned(size_t offset) noexcept -{ - const size_t page_size_ = page_size(); - // Use integer division to round down to the nearest page alignment. - return offset / page_size_ * page_size_; -} + /** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ + inline size_t make_offset_page_aligned(size_t offset) noexcept + { + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; + } } // namespace mio @@ -1413,384 +1450,456 @@ inline size_t make_offset_page_aligned(size_t offset) noexcept // #include "mio/mmap.hpp" - -#include // std::error_code #include // std::shared_ptr +#include // std::error_code -namespace mio { - -/** - * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with - * `std::shared_ptr` semantics. - * - * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if - * shared semantics are not required. - */ -template< - access_mode AccessMode, - typename ByteT -> class basic_shared_mmap +namespace mio { - using impl_type = basic_mmap; - std::shared_ptr pimpl_; - -public: - using value_type = typename impl_type::value_type; - using size_type = typename impl_type::size_type; - using reference = typename impl_type::reference; - using const_reference = typename impl_type::const_reference; - using pointer = typename impl_type::pointer; - using const_pointer = typename impl_type::const_pointer; - using difference_type = typename impl_type::difference_type; - using iterator = typename impl_type::iterator; - using const_iterator = typename impl_type::const_iterator; - using reverse_iterator = typename impl_type::reverse_iterator; - using const_reverse_iterator = typename impl_type::const_reverse_iterator; - using iterator_category = typename impl_type::iterator_category; - using handle_type = typename impl_type::handle_type; - using mmap_type = impl_type; - - basic_shared_mmap() = default; - basic_shared_mmap(const basic_shared_mmap&) = default; - basic_shared_mmap& operator=(const basic_shared_mmap&) = default; - basic_shared_mmap(basic_shared_mmap&&) = default; - basic_shared_mmap& operator=(basic_shared_mmap&&) = default; - - /** Takes ownership of an existing mmap object. */ - basic_shared_mmap(mmap_type&& mmap) - : pimpl_(std::make_shared(std::move(mmap))) - {} - - /** Takes ownership of an existing mmap object. */ - basic_shared_mmap& operator=(mmap_type&& mmap) - { - pimpl_ = std::make_shared(std::move(mmap)); - return *this; - } - - /** Initializes this object with an already established shared mmap. */ - basic_shared_mmap(std::shared_ptr mmap) : pimpl_(std::move(mmap)) {} - /** Initializes this object with an already established shared mmap. */ - basic_shared_mmap& operator=(std::shared_ptr mmap) - { - pimpl_ = std::move(mmap); - return *this; - } - -#ifdef __cpp_exceptions /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. + * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with + * `std::shared_ptr` semantics. + * + * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if + * shared semantics are not required. */ - template - basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) + template + class basic_shared_mmap { - std::error_code error; - map(path, offset, length, error); - if(error) { throw std::system_error(error); } - } + using impl_type = basic_mmap; + std::shared_ptr pimpl_; - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(handle, offset, length, error); - if(error) { throw std::system_error(error); } - } -#endif // __cpp_exceptions + public: + using value_type = typename impl_type::value_type; + using size_type = typename impl_type::size_type; + using reference = typename impl_type::reference; + using const_reference = typename impl_type::const_reference; + using pointer = typename impl_type::pointer; + using const_pointer = typename impl_type::const_pointer; + using difference_type = typename impl_type::difference_type; + using iterator = typename impl_type::iterator; + using const_iterator = typename impl_type::const_iterator; + using reverse_iterator = typename impl_type::reverse_iterator; + using const_reverse_iterator = typename impl_type::const_reverse_iterator; + using iterator_category = typename impl_type::iterator_category; + using handle_type = typename impl_type::handle_type; + using mmap_type = impl_type; + + basic_shared_mmap() = default; + basic_shared_mmap(const basic_shared_mmap&) = default; + basic_shared_mmap& operator=(const basic_shared_mmap&) = default; + basic_shared_mmap(basic_shared_mmap&&) = default; + basic_shared_mmap& operator=(basic_shared_mmap&&) = default; + + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap(mmap_type&& mmap) + : pimpl_(std::make_shared(std::move(mmap))) + { + } - /** - * If this is a read-write mapping and the last reference to the mapping, - * the destructor invokes sync. Regardless of the access mode, unmap is - * invoked as a final step. - */ - ~basic_shared_mmap() = default; + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap& operator=(mmap_type&& mmap) + { + pimpl_ = std::make_shared(std::move(mmap)); + return *this; + } - /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ - std::shared_ptr get_shared_ptr() { return pimpl_; } + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap(std::shared_ptr mmap) + : pimpl_(std::move(mmap)) + { + } - /** - * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, - * however, a mapped region of a file gets its own handle, which is returned by - * 'mapping_handle'. - */ - handle_type file_handle() const noexcept - { - return pimpl_ ? pimpl_->file_handle() : invalid_handle; - } + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap& operator=(std::shared_ptr mmap) + { + pimpl_ = std::move(mmap); + return *this; + } - handle_type mapping_handle() const noexcept - { - return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; - } +#ifdef __cpp_exceptions + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template + basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(path, offset, length, error); + if (error) + { + throw std::system_error(error); + } + } - /** Returns whether a valid memory mapping has been created. */ - bool is_open() const noexcept { return pimpl_ && pimpl_->is_open(); } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(handle, offset, length, error); + if (error) + { + throw std::system_error(error); + } + } +#endif // __cpp_exceptions - /** - * Returns true if no mapping was established, that is, conceptually the - * same as though the length that was mapped was 0. This function is - * provided so that this class has Container semantics. - */ - bool empty() const noexcept { return !pimpl_ || pimpl_->empty(); } + /** + * If this is a read-write mapping and the last reference to the mapping, + * the destructor invokes sync. Regardless of the access mode, unmap is + * invoked as a final step. + */ + ~basic_shared_mmap() = default; - /** - * `size` and `length` both return the logical length, i.e. the number of bytes - * user requested to be mapped, while `mapped_length` returns the actual number of - * bytes that were mapped which is a multiple of the underlying operating system's - * page allocation granularity. - */ - size_type size() const noexcept { return pimpl_ ? pimpl_->length() : 0; } - size_type length() const noexcept { return pimpl_ ? pimpl_->length() : 0; } - size_type mapped_length() const noexcept - { - return pimpl_ ? pimpl_->mapped_length() : 0; - } + /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ + std::shared_ptr get_shared_ptr() + { + return pimpl_; + } - /** - * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping - * exists. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > pointer data() noexcept { return pimpl_->data(); } - const_pointer data() const noexcept { return pimpl_ ? pimpl_->data() : nullptr; } + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept + { + return pimpl_ ? pimpl_->file_handle() : invalid_handle; + } - /** - * Returns an iterator to the first requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - iterator begin() noexcept { return pimpl_->begin(); } - const_iterator begin() const noexcept { return pimpl_->begin(); } - const_iterator cbegin() const noexcept { return pimpl_->cbegin(); } + handle_type mapping_handle() const noexcept + { + return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; + } - /** - * Returns an iterator one past the last requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > iterator end() noexcept { return pimpl_->end(); } - const_iterator end() const noexcept { return pimpl_->end(); } - const_iterator cend() const noexcept { return pimpl_->cend(); } + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept + { + return pimpl_ && pimpl_->is_open(); + } - /** - * Returns a reverse iterator to the last memory mapped byte, if a valid - * memory mapping exists, otherwise this function call is undefined - * behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > reverse_iterator rbegin() noexcept { return pimpl_->rbegin(); } - const_reverse_iterator rbegin() const noexcept { return pimpl_->rbegin(); } - const_reverse_iterator crbegin() const noexcept { return pimpl_->crbegin(); } + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept + { + return !pimpl_ || pimpl_->empty(); + } - /** - * Returns a reverse iterator past the first mapped byte, if a valid memory - * mapping exists, otherwise this function call is undefined behaviour. - */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > reverse_iterator rend() noexcept { return pimpl_->rend(); } - const_reverse_iterator rend() const noexcept { return pimpl_->rend(); } - const_reverse_iterator crend() const noexcept { return pimpl_->crend(); } + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept + { + return pimpl_ ? pimpl_->length() : 0; + } + size_type length() const noexcept + { + return pimpl_ ? pimpl_->length() : 0; + } + size_type mapped_length() const noexcept + { + return pimpl_ ? pimpl_->mapped_length() : 0; + } - /** - * Returns a reference to the `i`th byte from the first requested byte (as returned - * by `data`). If this is invoked when no valid memory mapping has been created - * prior to this call, undefined behaviour ensues. - */ - reference operator[](const size_type i) noexcept { return (*pimpl_)[i]; } - const_reference operator[](const size_type i) const noexcept { return (*pimpl_)[i]; } + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template::type> + pointer data() noexcept + { + return pimpl_->data(); + } + const_pointer data() const noexcept + { + return pimpl_ ? pimpl_->data() : nullptr; + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - template - void map(const String& path, const size_type offset, - const size_type length, std::error_code& error) - { - map_impl(path, offset, length, error); - } + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + iterator begin() noexcept + { + return pimpl_->begin(); + } + const_iterator begin() const noexcept + { + return pimpl_->begin(); + } + const_iterator cbegin() const noexcept + { + return pimpl_->cbegin(); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * The entire file is mapped. - */ - template - void map(const String& path, std::error_code& error) - { - map_impl(path, 0, map_entire_file, error); - } + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template::type> + iterator end() noexcept + { + return pimpl_->end(); + } + const_iterator end() const noexcept + { + return pimpl_->end(); + } + const_iterator cend() const noexcept + { + return pimpl_->cend(); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - void map(const handle_type handle, const size_type offset, - const size_type length, std::error_code& error) - { - map_impl(handle, offset, length, error); - } + /** + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. + */ + template::type> + reverse_iterator rbegin() noexcept + { + return pimpl_->rbegin(); + } + const_reverse_iterator rbegin() const noexcept + { + return pimpl_->rbegin(); + } + const_reverse_iterator crbegin() const noexcept + { + return pimpl_->crbegin(); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * The entire file is mapped. - */ - void map(const handle_type handle, std::error_code& error) - { - map_impl(handle, 0, map_entire_file, error); - } + /** + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. + */ + template::type> + reverse_iterator rend() noexcept + { + return pimpl_->rend(); + } + const_reverse_iterator rend() const noexcept + { + return pimpl_->rend(); + } + const_reverse_iterator crend() const noexcept + { + return pimpl_->crend(); + } - /** - * If a valid memory mapping has been created prior to this call, this call - * instructs the kernel to unmap the memory region and disassociate this object - * from the file. - * - * The file handle associated with the file that is mapped is only closed if the - * mapping was created using a file path. If, on the other hand, an existing - * file handle was used to create the mapping, the file handle is not closed. - */ - void unmap() { if(pimpl_) pimpl_->unmap(); } + /** + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. + */ + reference operator[](const size_type i) noexcept + { + return (*pimpl_)[i]; + } + const_reference operator[](const size_type i) const noexcept + { + return (*pimpl_)[i]; + } - void swap(basic_shared_mmap& other) { pimpl_.swap(other.pimpl_); } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template + void map(const String& path, const size_type offset, const size_type length, std::error_code& error) + { + map_impl(path, offset, length, error); + } - /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ - template< - access_mode A = AccessMode, - typename = typename std::enable_if::type - > void sync(std::error_code& error) { if(pimpl_) pimpl_->sync(error); } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. + */ + template + void map(const String& path, std::error_code& error) + { + map_impl(path, 0, map_entire_file, error); + } - /** All operators compare the underlying `basic_mmap`'s addresses. */ + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error) + { + map_impl(handle, offset, length, error); + } - friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ == b.pimpl_; - } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code& error) + { + map_impl(handle, 0, map_entire_file, error); + } - friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return !(a == b); - } + /** + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. + * + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. + */ + void unmap() + { + if (pimpl_) + pimpl_->unmap(); + } - friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ < b.pimpl_; - } + void swap(basic_shared_mmap& other) + { + pimpl_.swap(other.pimpl_); + } - friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ <= b.pimpl_; - } + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template::type> + void sync(std::error_code& error) + { + if (pimpl_) + pimpl_->sync(error); + } - friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ > b.pimpl_; - } + /** All operators compare the underlying `basic_mmap`'s addresses. */ - friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ >= b.pimpl_; - } + friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ == b.pimpl_; + } + + friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return !(a == b); + } + + friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ < b.pimpl_; + } + + friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ <= b.pimpl_; + } -private: - template - void map_impl(const MappingToken& token, const size_type offset, - const size_type length, std::error_code& error) - { - if(!pimpl_) + friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) { - mmap_type mmap = make_mmap(token, offset, length, error); - if(error) { return; } - pimpl_ = std::make_shared(std::move(mmap)); + return a.pimpl_ > b.pimpl_; } - else + + friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) { - pimpl_->map(token, offset, length, error); + return a.pimpl_ >= b.pimpl_; } - } -}; -/** - * This is the basis for all read-only mmap objects and should be preferred over - * directly using basic_shared_mmap. - */ -template -using basic_shared_mmap_source = basic_shared_mmap; + private: + template + void map_impl(const MappingToken& token, const size_type offset, const size_type length, std::error_code& error) + { + if (!pimpl_) + { + mmap_type mmap = make_mmap(token, offset, length, error); + if (error) + { + return; + } + pimpl_ = std::make_shared(std::move(mmap)); + } + else + { + pimpl_->map(token, offset, length, error); + } + } + }; -/** - * This is the basis for all read-write mmap objects and should be preferred over - * directly using basic_shared_mmap. - */ -template -using basic_shared_mmap_sink = basic_shared_mmap; + /** + * This is the basis for all read-only mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ + template + using basic_shared_mmap_source = basic_shared_mmap; -/** - * These aliases cover the most common use cases, both representing a raw byte stream - * (either with a char or an unsigned char/uint8_t). - */ -using shared_mmap_source = basic_shared_mmap_source; -using shared_ummap_source = basic_shared_mmap_source; + /** + * This is the basis for all read-write mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ + template + using basic_shared_mmap_sink = basic_shared_mmap; + + /** + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). + */ + using shared_mmap_source = basic_shared_mmap_source; + using shared_ummap_source = basic_shared_mmap_source; -using shared_mmap_sink = basic_shared_mmap_sink; -using shared_ummap_sink = basic_shared_mmap_sink; + using shared_mmap_sink = basic_shared_mmap_sink; + using shared_ummap_sink = basic_shared_mmap_sink; } // namespace mio @@ -1807,14 +1916,14 @@ using shared_ummap_sink = basic_shared_mmap_sink; #include #include #include +#include #include #include -#include #include #include -#include #include +#include #include /** @file @@ -1828,19 +1937,19 @@ using shared_ummap_sink = basic_shared_mmap_sink; #include #if defined(_WIN32) -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# undef max -# undef min +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#undef max +#undef min #elif defined(__linux__) -# include +#include #endif - /** Helper macro which should be #defined as "inline" - * in the single header version - */ +/** Helper macro which should be #defined as "inline" + * in the single header version + */ #define CSV_INLINE inline #include @@ -1853,98 +1962,100 @@ using shared_ummap_sink = basic_shared_mmap_sink; // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - #ifndef NONSTD_SV_LITE_H_INCLUDED #define NONSTD_SV_LITE_H_INCLUDED -#define string_view_lite_MAJOR 1 -#define string_view_lite_MINOR 1 -#define string_view_lite_PATCH 0 +#define string_view_lite_MAJOR 1 +#define string_view_lite_MINOR 1 +#define string_view_lite_PATCH 0 -#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH) +#define string_view_lite_VERSION \ + nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH) -#define nssv_STRINGIFY( x ) nssv_STRINGIFY_( x ) -#define nssv_STRINGIFY_( x ) #x +#define nssv_STRINGIFY(x) nssv_STRINGIFY_(x) +#define nssv_STRINGIFY_(x) #x // string-view lite configuration: -#define nssv_STRING_VIEW_DEFAULT 0 -#define nssv_STRING_VIEW_NONSTD 1 -#define nssv_STRING_VIEW_STD 2 +#define nssv_STRING_VIEW_DEFAULT 0 +#define nssv_STRING_VIEW_NONSTD 1 +#define nssv_STRING_VIEW_STD 2 -#if !defined( nssv_CONFIG_SELECT_STRING_VIEW ) -# define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD ) +#if !defined(nssv_CONFIG_SELECT_STRING_VIEW) +#define nssv_CONFIG_SELECT_STRING_VIEW (nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD) #endif -#if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW ) -# error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_... +#if defined(nssv_CONFIG_SELECT_STD_STRING_VIEW) || defined(nssv_CONFIG_SELECT_NONSTD_STRING_VIEW) +#error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_... #endif -#ifndef nssv_CONFIG_STD_SV_OPERATOR -# define nssv_CONFIG_STD_SV_OPERATOR 0 +#ifndef nssv_CONFIG_STD_SV_OPERATOR +#define nssv_CONFIG_STD_SV_OPERATOR 0 #endif -#ifndef nssv_CONFIG_USR_SV_OPERATOR -# define nssv_CONFIG_USR_SV_OPERATOR 1 +#ifndef nssv_CONFIG_USR_SV_OPERATOR +#define nssv_CONFIG_USR_SV_OPERATOR 1 #endif -#ifdef nssv_CONFIG_CONVERSION_STD_STRING -# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING -# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING +#ifdef nssv_CONFIG_CONVERSION_STD_STRING +#define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING +#define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING #endif -#ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS -# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1 +#ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS +#define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1 #endif -#ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1 +#ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS +#define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1 #endif // Control presence of exception handling (try and auto discover): #ifndef nssv_CONFIG_NO_EXCEPTIONS -# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) -# define nssv_CONFIG_NO_EXCEPTIONS 0 -# else -# define nssv_CONFIG_NO_EXCEPTIONS 1 -# endif +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define nssv_CONFIG_NO_EXCEPTIONS 0 +#else +#define nssv_CONFIG_NO_EXCEPTIONS 1 +#endif #endif // C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. -#ifndef nssv_CPLUSPLUS -# if defined(_MSVC_LANG ) && !defined(__clang__) -# define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) -# else -# define nssv_CPLUSPLUS __cplusplus -# endif +#ifndef nssv_CPLUSPLUS +#if defined(_MSVC_LANG) && !defined(__clang__) +#define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) +#else +#define nssv_CPLUSPLUS __cplusplus +#endif #endif -#define nssv_CPP98_OR_GREATER ( nssv_CPLUSPLUS >= 199711L ) -#define nssv_CPP11_OR_GREATER ( nssv_CPLUSPLUS >= 201103L ) -#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L ) -#define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L ) -#define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L ) -#define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202000L ) +#define nssv_CPP98_OR_GREATER (nssv_CPLUSPLUS >= 199711L) +#define nssv_CPP11_OR_GREATER (nssv_CPLUSPLUS >= 201103L) +#define nssv_CPP11_OR_GREATER_ (nssv_CPLUSPLUS >= 201103L) +#define nssv_CPP14_OR_GREATER (nssv_CPLUSPLUS >= 201402L) +#define nssv_CPP17_OR_GREATER (nssv_CPLUSPLUS >= 201703L) +#define nssv_CPP20_OR_GREATER (nssv_CPLUSPLUS >= 202000L) // use C++17 std::string_view if available and requested: -#if nssv_CPP17_OR_GREATER && defined(__has_include ) -# if __has_include( ) -# define nssv_HAVE_STD_STRING_VIEW 1 -# else -# define nssv_HAVE_STD_STRING_VIEW 0 -# endif +#if nssv_CPP17_OR_GREATER && defined(__has_include) +#if __has_include( ) +#define nssv_HAVE_STD_STRING_VIEW 1 +#else +#define nssv_HAVE_STD_STRING_VIEW 0 +#endif #else -# define nssv_HAVE_STD_STRING_VIEW 0 +#define nssv_HAVE_STD_STRING_VIEW 0 #endif -#define nssv_USES_STD_STRING_VIEW ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) ) +#define nssv_USES_STD_STRING_VIEW \ + ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || \ + ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW)) -#define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW ) -#define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH +#define nssv_HAVE_STARTS_WITH (nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW) +#define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH // // Use C++17 std::string_view: @@ -1958,57 +2069,58 @@ using shared_ummap_sink = basic_shared_mmap_sink; #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd { - -template< class CharT, class Traits, class Allocator = std::allocator > -std::basic_string -to_string( std::basic_string_view v, Allocator const & a = Allocator() ) +namespace nonstd { - return std::basic_string( v.begin(), v.end(), a ); -} -template< class CharT, class Traits, class Allocator > -std::basic_string_view -to_string_view( std::basic_string const & s ) -{ - return std::basic_string_view( s.data(), s.size() ); -} + template> + std::basic_string to_string(std::basic_string_view v, Allocator const& a = Allocator()) + { + return std::basic_string(v.begin(), v.end(), a); + } + + template + std::basic_string_view to_string_view(std::basic_string const& s) + { + return std::basic_string_view(s.data(), s.size()); + } -// Literal operators sv and _sv: + // Literal operators sv and _sv: #if nssv_CONFIG_STD_SV_OPERATOR -using namespace std::literals::string_view_literals; + using namespace std::literals::string_view_literals; #endif #if nssv_CONFIG_USR_SV_OPERATOR -inline namespace literals { -inline namespace string_view_literals { - + inline namespace literals + { + inline namespace string_view_literals + { -constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) -{ - return std::string_view{ str, len }; -} + constexpr std::string_view operator"" _sv(const char* str, size_t len) noexcept // (1) + { + return std::string_view{ str, len }; + } -constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) -{ - return std::u16string_view{ str, len }; -} + constexpr std::u16string_view operator"" _sv(const char16_t* str, size_t len) noexcept // (2) + { + return std::u16string_view{ str, len }; + } -constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) -{ - return std::u32string_view{ str, len }; -} + constexpr std::u32string_view operator"" _sv(const char32_t* str, size_t len) noexcept // (3) + { + return std::u32string_view{ str, len }; + } -constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) -{ - return std::wstring_view{ str, len }; -} + constexpr std::wstring_view operator"" _sv(const wchar_t* str, size_t len) noexcept // (4) + { + return std::wstring_view{ str, len }; + } -}} // namespace literals::string_view_literals + } // namespace string_view_literals + } // namespace literals #endif // nssv_CONFIG_USR_SV_OPERATOR @@ -2016,24 +2128,25 @@ constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) no #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd { +namespace nonstd +{ -using std::string_view; -using std::wstring_view; -using std::u16string_view; -using std::u32string_view; -using std::basic_string_view; + using std::basic_string_view; + using std::string_view; + using std::u16string_view; + using std::u32string_view; + using std::wstring_view; -// literal "sv" and "_sv", see above + // literal "sv" and "_sv", see above -using std::operator==; -using std::operator!=; -using std::operator<; -using std::operator<=; -using std::operator>; -using std::operator>=; + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; -using std::operator<<; + using std::operator<<; } // namespace nonstd @@ -2056,115 +2169,115 @@ using std::operator<<; // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) -#if defined(_MSC_VER ) && !defined(__clang__) -# define nssv_COMPILER_MSVC_VER (_MSC_VER ) -# define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#if defined(_MSC_VER) && !defined(__clang__) +#define nssv_COMPILER_MSVC_VER (_MSC_VER) +#define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) #else -# define nssv_COMPILER_MSVC_VER 0 -# define nssv_COMPILER_MSVC_VERSION 0 +#define nssv_COMPILER_MSVC_VER 0 +#define nssv_COMPILER_MSVC_VERSION 0 #endif -#define nssv_COMPILER_VERSION( major, minor, patch ) (10 * ( 10 * major + minor) + patch) +#define nssv_COMPILER_VERSION(major, minor, patch) (10 * (10 * major + minor) + patch) #if defined(__clang__) -# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else -# define nssv_COMPILER_CLANG_VERSION 0 +#define nssv_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) -# define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else -# define nssv_COMPILER_GNUC_VERSION 0 +#define nssv_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): -#define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) +#define nssv_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi)) // Presence of language and library features: #ifdef _HAS_CPP0X -# define nssv_HAS_CPP0X _HAS_CPP0X +#define nssv_HAS_CPP0X _HAS_CPP0X #else -# define nssv_HAS_CPP0X 0 +#define nssv_HAS_CPP0X 0 #endif // Unless defined otherwise below, consider VC14 as C++11 for variant-lite: #if nssv_COMPILER_MSVC_VER >= 1900 -# undef nssv_CPP11_OR_GREATER -# define nssv_CPP11_OR_GREATER 1 +#undef nssv_CPP11_OR_GREATER +#define nssv_CPP11_OR_GREATER 1 #endif -#define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500) -#define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600) -#define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700) -#define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800) -#define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900) -#define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910) +#define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500) +#define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600) +#define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700) +#define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800) +#define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900) +#define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910) -#define nssv_CPP14_000 (nssv_CPP14_OR_GREATER) -#define nssv_CPP17_000 (nssv_CPP17_OR_GREATER) +#define nssv_CPP14_000 (nssv_CPP14_OR_GREATER) +#define nssv_CPP17_000 (nssv_CPP17_OR_GREATER) // Presence of C++11 language features: -#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140 -#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140 -#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140 -#define nssv_HAVE_NOEXCEPT nssv_CPP11_140 -#define nssv_HAVE_NULLPTR nssv_CPP11_100 -#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140 -#define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140 +#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140 +#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140 +#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140 +#define nssv_HAVE_NOEXCEPT nssv_CPP11_140 +#define nssv_HAVE_NULLPTR nssv_CPP11_100 +#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140 +#define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140 #define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140 -#define nssv_HAVE_WCHAR16_T nssv_CPP11_100 -#define nssv_HAVE_WCHAR32_T nssv_CPP11_100 +#define nssv_HAVE_WCHAR16_T nssv_CPP11_100 +#define nssv_HAVE_WCHAR32_T nssv_CPP11_100 -#if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) ) -# define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140 +#if !((nssv_CPP11 && nssv_COMPILER_CLANG_VERSION) || nssv_BETWEEN(nssv_COMPILER_CLANG_VERSION, 300, 400)) +#define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140 #endif // Presence of C++14 language features: -#define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000 +#define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000 // Presence of C++17 language features: -#define nssv_HAVE_NODISCARD nssv_CPP17_000 +#define nssv_HAVE_NODISCARD nssv_CPP17_000 // Presence of C++ library features: -#define nssv_HAVE_STD_HASH nssv_CPP11_120 +#define nssv_HAVE_STD_HASH nssv_CPP11_120 // C++ feature usage: #if nssv_HAVE_CONSTEXPR_11 -# define nssv_constexpr constexpr +#define nssv_constexpr constexpr #else -# define nssv_constexpr /*constexpr*/ +#define nssv_constexpr /*constexpr*/ #endif -#if nssv_HAVE_CONSTEXPR_14 -# define nssv_constexpr14 constexpr +#if nssv_HAVE_CONSTEXPR_14 +#define nssv_constexpr14 constexpr #else -# define nssv_constexpr14 /*constexpr*/ +#define nssv_constexpr14 /*constexpr*/ #endif #if nssv_HAVE_EXPLICIT_CONVERSION -# define nssv_explicit explicit +#define nssv_explicit explicit #else -# define nssv_explicit /*explicit*/ +#define nssv_explicit /*explicit*/ #endif #if nssv_HAVE_INLINE_NAMESPACE -# define nssv_inline_ns inline +#define nssv_inline_ns inline #else -# define nssv_inline_ns /*inline*/ +#define nssv_inline_ns /*inline*/ #endif #if nssv_HAVE_NOEXCEPT -# define nssv_noexcept noexcept +#define nssv_noexcept noexcept #else -# define nssv_noexcept /*noexcept*/ +#define nssv_noexcept /*noexcept*/ #endif //#if nssv_HAVE_REF_QUALIFIER @@ -2176,15 +2289,15 @@ using std::operator<<; //#endif #if nssv_HAVE_NULLPTR -# define nssv_nullptr nullptr +#define nssv_nullptr nullptr #else -# define nssv_nullptr NULL +#define nssv_nullptr NULL #endif #if nssv_HAVE_NODISCARD -# define nssv_nodiscard [[nodiscard]] +#define nssv_nodiscard [[nodiscard]] #else -# define nssv_nodiscard /*[[nodiscard]]*/ +#define nssv_nodiscard /*[[nodiscard]]*/ #endif // Additional includes: @@ -2194,45 +2307,45 @@ using std::operator<<; #include #include #include -#include // std::char_traits<> +#include // std::char_traits<> -#if ! nssv_CONFIG_NO_EXCEPTIONS -# include +#if !nssv_CONFIG_NO_EXCEPTIONS +#include #endif #if nssv_CPP11_OR_GREATER -# include +#include #endif // Clang, GNUC, MSVC warning suppression macros: #if defined(__clang__) -# pragma clang diagnostic ignored "-Wreserved-user-defined-literal" -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wuser-defined-literals" +#pragma clang diagnostic ignored "-Wreserved-user-defined-literal" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wuser-defined-literals" #elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wliteral-suffix" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wliteral-suffix" #endif // __clang__ #if nssv_COMPILER_MSVC_VERSION >= 140 -# define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] -# define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) -# define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) +#define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] +#define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress : code)) +#define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable : codes)) #else -# define nssv_SUPPRESS_MSGSL_WARNING(expr) -# define nssv_SUPPRESS_MSVC_WARNING(code, descr) -# define nssv_DISABLE_MSVC_WARNINGS(codes) +#define nssv_SUPPRESS_MSGSL_WARNING(expr) +#define nssv_SUPPRESS_MSVC_WARNING(code, descr) +#define nssv_DISABLE_MSVC_WARNINGS(codes) #endif #if defined(__clang__) -# define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +#define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") #elif defined(__GNUC__) -# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +#define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") #elif nssv_COMPILER_MSVC_VERSION >= 140 -# define nssv_RESTORE_WARNINGS() __pragma(warning(pop )) +#define nssv_RESTORE_WARNINGS() __pragma(warning(pop)) #else -# define nssv_RESTORE_WARNINGS() +#define nssv_RESTORE_WARNINGS() #endif // Suppress the following MSVC (GSL) warnings: @@ -2242,722 +2355,763 @@ using std::operator<<; // use brace initialization, gsl::narrow_cast or gsl::narow // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead -nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 ) -//nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" ) -//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix ) +nssv_DISABLE_MSVC_WARNINGS(4455 26481 26472) + // nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" ) + // nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix ) -namespace nonstd { namespace sv_lite { + namespace nonstd +{ + namespace sv_lite + { -template -< - class CharT, - class Traits = std::char_traits -> -class basic_string_view; + template> + class basic_string_view; -// -// basic_string_view: -// + // + // basic_string_view: + // -template -< - class CharT, - class Traits /* = std::char_traits */ -> -class basic_string_view -{ -public: - // Member types: + template< + class CharT, + class Traits /* = std::char_traits */ + > + class basic_string_view + { + public: + // Member types: - typedef Traits traits_type; - typedef CharT value_type; + typedef Traits traits_type; + typedef CharT value_type; - typedef CharT * pointer; - typedef CharT const * const_pointer; - typedef CharT & reference; - typedef CharT const & const_reference; + typedef CharT* pointer; + typedef CharT const* const_pointer; + typedef CharT& reference; + typedef CharT const& const_reference; - typedef const_pointer iterator; - typedef const_pointer const_iterator; - typedef std::reverse_iterator< const_iterator > reverse_iterator; - typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + typedef const_pointer iterator; + typedef const_pointer const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - // 24.4.2.1 Construction and assignment: + // 24.4.2.1 Construction and assignment: - nssv_constexpr basic_string_view() nssv_noexcept - : data_( nssv_nullptr ) - , size_( 0 ) - {} + nssv_constexpr basic_string_view() nssv_noexcept + : data_(nssv_nullptr) + , size_(0) + { + } #if nssv_CPP11_OR_GREATER - nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default; + nssv_constexpr basic_string_view(basic_string_view const& other) nssv_noexcept = default; #else - nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept - : data_( other.data_) - , size_( other.size_) - {} + nssv_constexpr basic_string_view(basic_string_view const& other) nssv_noexcept + : data_(other.data_) + , size_(other.size_) + { + } #endif - nssv_constexpr basic_string_view( CharT const * s, size_type count ) - : data_( s ) - , size_( count ) - {} + nssv_constexpr basic_string_view(CharT const* s, size_type count) + : data_(s) + , size_(count) + { + } - nssv_constexpr basic_string_view( CharT const * s) - : data_( s ) - , size_( Traits::length(s) ) - {} + nssv_constexpr basic_string_view(CharT const* s) + : data_(s) + , size_(Traits::length(s)) + { + } - // Assignment: + // Assignment: #if nssv_CPP11_OR_GREATER - nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default; + nssv_constexpr14 basic_string_view& operator=(basic_string_view const& other) nssv_noexcept = default; #else - nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept - { - data_ = other.data_; - size_ = other.size_; - return *this; - } + nssv_constexpr14 basic_string_view& operator=(basic_string_view const& other) nssv_noexcept + { + data_ = other.data_; + size_ = other.size_; + return *this; + } #endif - // 24.4.2.2 Iterator support: + // 24.4.2.2 Iterator support: - nssv_constexpr const_iterator begin() const nssv_noexcept { return data_; } - nssv_constexpr const_iterator end() const nssv_noexcept { return data_ + size_; } + nssv_constexpr const_iterator begin() const nssv_noexcept + { + return data_; + } + nssv_constexpr const_iterator end() const nssv_noexcept + { + return data_ + size_; + } - nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); } - nssv_constexpr const_iterator cend() const nssv_noexcept { return end(); } + nssv_constexpr const_iterator cbegin() const nssv_noexcept + { + return begin(); + } + nssv_constexpr const_iterator cend() const nssv_noexcept + { + return end(); + } - nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept { return const_reverse_iterator( end() ); } - nssv_constexpr const_reverse_iterator rend() const nssv_noexcept { return const_reverse_iterator( begin() ); } + nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept + { + return const_reverse_iterator(end()); + } + nssv_constexpr const_reverse_iterator rend() const nssv_noexcept + { + return const_reverse_iterator(begin()); + } - nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); } - nssv_constexpr const_reverse_iterator crend() const nssv_noexcept { return rend(); } + nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept + { + return rbegin(); + } + nssv_constexpr const_reverse_iterator crend() const nssv_noexcept + { + return rend(); + } - // 24.4.2.3 Capacity: + // 24.4.2.3 Capacity: - nssv_constexpr size_type size() const nssv_noexcept { return size_; } - nssv_constexpr size_type length() const nssv_noexcept { return size_; } - nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); } + nssv_constexpr size_type size() const nssv_noexcept + { + return size_; + } + nssv_constexpr size_type length() const nssv_noexcept + { + return size_; + } + nssv_constexpr size_type max_size() const nssv_noexcept + { + return (std::numeric_limits::max)(); + } - // since C++20 - nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept - { - return 0 == size_; - } + // since C++20 + nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept + { + return 0 == size_; + } - // 24.4.2.4 Element access: + // 24.4.2.4 Element access: - nssv_constexpr const_reference operator[]( size_type pos ) const - { - return data_at( pos ); - } + nssv_constexpr const_reference operator[](size_type pos) const + { + return data_at(pos); + } - nssv_constexpr14 const_reference at( size_type pos ) const - { + nssv_constexpr14 const_reference at(size_type pos) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert( pos < size() ); + assert(pos < size()); #else - if ( pos >= size() ) - { - throw std::out_of_range("nonst::string_view::at()"); - } + if (pos >= size()) + { + throw std::out_of_range("nonst::string_view::at()"); + } #endif - return data_at( pos ); - } + return data_at(pos); + } - nssv_constexpr const_reference front() const { return data_at( 0 ); } - nssv_constexpr const_reference back() const { return data_at( size() - 1 ); } + nssv_constexpr const_reference front() const + { + return data_at(0); + } + nssv_constexpr const_reference back() const + { + return data_at(size() - 1); + } - nssv_constexpr const_pointer data() const nssv_noexcept { return data_; } + nssv_constexpr const_pointer data() const nssv_noexcept + { + return data_; + } - // 24.4.2.5 Modifiers: + // 24.4.2.5 Modifiers: - nssv_constexpr14 void remove_prefix( size_type n ) - { - assert( n <= size() ); - data_ += n; - size_ -= n; - } + nssv_constexpr14 void remove_prefix(size_type n) + { + assert(n <= size()); + data_ += n; + size_ -= n; + } - nssv_constexpr14 void remove_suffix( size_type n ) - { - assert( n <= size() ); - size_ -= n; - } + nssv_constexpr14 void remove_suffix(size_type n) + { + assert(n <= size()); + size_ -= n; + } - nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept - { - using std::swap; - swap( data_, other.data_ ); - swap( size_, other.size_ ); - } + nssv_constexpr14 void swap(basic_string_view& other) nssv_noexcept + { + using std::swap; + swap(data_, other.data_); + swap(size_, other.size_); + } - // 24.4.2.6 String operations: + // 24.4.2.6 String operations: - size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const - { + size_type copy(CharT* dest, size_type n, size_type pos = 0) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert( pos <= size() ); + assert(pos <= size()); #else - if ( pos > size() ) - { - throw std::out_of_range("nonst::string_view::copy()"); - } + if (pos > size()) + { + throw std::out_of_range("nonst::string_view::copy()"); + } #endif - const size_type rlen = (std::min)( n, size() - pos ); + const size_type rlen = (std::min)(n, size() - pos); - (void) Traits::copy( dest, data() + pos, rlen ); + (void)Traits::copy(dest, data() + pos, rlen); - return rlen; - } + return rlen; + } - nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const - { + nssv_constexpr14 basic_string_view substr(size_type pos = 0, size_type n = npos) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert( pos <= size() ); + assert(pos <= size()); #else - if ( pos > size() ) - { - throw std::out_of_range("nonst::string_view::substr()"); - } + if (pos > size()) + { + throw std::out_of_range("nonst::string_view::substr()"); + } #endif - return basic_string_view( data() + pos, (std::min)( n, size() - pos ) ); - } + return basic_string_view(data() + pos, (std::min)(n, size() - pos)); + } - // compare(), 6x: + // compare(), 6x: - nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1) - { - if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) ) - return result; + nssv_constexpr14 int compare(basic_string_view other) const nssv_noexcept // (1) + { + if (const int result = Traits::compare(data(), other.data(), (std::min)(size(), other.size()))) + return result; - return size() == other.size() ? 0 : size() < other.size() ? -1 : 1; - } + return size() == other.size() ? 0 : size() < other.size() ? -1 : 1; + } - nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2) - { - return substr( pos1, n1 ).compare( other ); - } + nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other) const // (2) + { + return substr(pos1, n1).compare(other); + } - nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3) - { - return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) ); - } + nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2) const // (3) + { + return substr(pos1, n1).compare(other.substr(pos2, n2)); + } - nssv_constexpr int compare( CharT const * s ) const // (4) - { - return compare( basic_string_view( s ) ); - } + nssv_constexpr int compare(CharT const* s) const // (4) + { + return compare(basic_string_view(s)); + } - nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5) - { - return substr( pos1, n1 ).compare( basic_string_view( s ) ); - } + nssv_constexpr int compare(size_type pos1, size_type n1, CharT const* s) const // (5) + { + return substr(pos1, n1).compare(basic_string_view(s)); + } + + nssv_constexpr int compare(size_type pos1, size_type n1, CharT const* s, size_type n2) const // (6) + { + return substr(pos1, n1).compare(basic_string_view(s, n2)); + } + + // 24.4.2.7 Searching: + + // starts_with(), 3x, since C++20: + + nssv_constexpr bool starts_with(basic_string_view v) const nssv_noexcept // (1) + { + return size() >= v.size() && compare(0, v.size(), v) == 0; + } + + nssv_constexpr bool starts_with(CharT c) const nssv_noexcept // (2) + { + return starts_with(basic_string_view(&c, 1)); + } + + nssv_constexpr bool starts_with(CharT const* s) const // (3) + { + return starts_with(basic_string_view(s)); + } + + // ends_with(), 3x, since C++20: + + nssv_constexpr bool ends_with(basic_string_view v) const nssv_noexcept // (1) + { + return size() >= v.size() && compare(size() - v.size(), npos, v) == 0; + } + + nssv_constexpr bool ends_with(CharT c) const nssv_noexcept // (2) + { + return ends_with(basic_string_view(&c, 1)); + } + + nssv_constexpr bool ends_with(CharT const* s) const // (3) + { + return ends_with(basic_string_view(s)); + } + + // find(), 4x: + + nssv_constexpr14 size_type find(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) + { + return assert(v.size() == 0 || v.data() != nssv_nullptr), + pos >= size() ? npos : to_pos(std::search(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq)); + } + + nssv_constexpr14 size_type find(CharT c, size_type pos = 0) const nssv_noexcept // (2) + { + return find(basic_string_view(&c, 1), pos); + } + + nssv_constexpr14 size_type find(CharT const* s, size_type pos, size_type n) const // (3) + { + return find(basic_string_view(s, n), pos); + } + + nssv_constexpr14 size_type find(CharT const* s, size_type pos = 0) const // (4) + { + return find(basic_string_view(s), pos); + } + + // rfind(), 4x: + + nssv_constexpr14 size_type rfind(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) + { + if (size() < v.size()) + return npos; + + if (v.empty()) + return (std::min)(size(), pos); + + const_iterator last = cbegin() + (std::min)(size() - v.size(), pos) + v.size(); + const_iterator result = std::find_end(cbegin(), last, v.cbegin(), v.cend(), Traits::eq); + + return result != last ? size_type(result - cbegin()) : npos; + } + + nssv_constexpr14 size_type rfind(CharT c, size_type pos = npos) const nssv_noexcept // (2) + { + return rfind(basic_string_view(&c, 1), pos); + } + + nssv_constexpr14 size_type rfind(CharT const* s, size_type pos, size_type n) const // (3) + { + return rfind(basic_string_view(s, n), pos); + } + + nssv_constexpr14 size_type rfind(CharT const* s, size_type pos = npos) const // (4) + { + return rfind(basic_string_view(s), pos); + } + + // find_first_of(), 4x: + + nssv_constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) + { + return pos >= size() ? npos : to_pos(std::find_first_of(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq)); + } + + nssv_constexpr size_type find_first_of(CharT c, size_type pos = 0) const nssv_noexcept // (2) + { + return find_first_of(basic_string_view(&c, 1), pos); + } + + nssv_constexpr size_type find_first_of(CharT const* s, size_type pos, size_type n) const // (3) + { + return find_first_of(basic_string_view(s, n), pos); + } + + nssv_constexpr size_type find_first_of(CharT const* s, size_type pos = 0) const // (4) + { + return find_first_of(basic_string_view(s), pos); + } + + // find_last_of(), 4x: + + nssv_constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) + { + return empty() ? npos + : pos >= size() + ? find_last_of(v, size() - 1) + : to_pos(std::find_first_of(const_reverse_iterator(cbegin() + pos + 1), crend(), v.cbegin(), v.cend(), Traits::eq)); + } - nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6) - { - return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) ); - } + nssv_constexpr size_type find_last_of(CharT c, size_type pos = npos) const nssv_noexcept // (2) + { + return find_last_of(basic_string_view(&c, 1), pos); + } - // 24.4.2.7 Searching: + nssv_constexpr size_type find_last_of(CharT const* s, size_type pos, size_type count) const // (3) + { + return find_last_of(basic_string_view(s, count), pos); + } - // starts_with(), 3x, since C++20: + nssv_constexpr size_type find_last_of(CharT const* s, size_type pos = npos) const // (4) + { + return find_last_of(basic_string_view(s), pos); + } - nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept // (1) - { - return size() >= v.size() && compare( 0, v.size(), v ) == 0; - } + // find_first_not_of(), 4x: - nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept // (2) - { - return starts_with( basic_string_view( &c, 1 ) ); - } + nssv_constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) + { + return pos >= size() ? npos : to_pos(std::find_if(cbegin() + pos, cend(), not_in_view(v))); + } - nssv_constexpr bool starts_with( CharT const * s ) const // (3) - { - return starts_with( basic_string_view( s ) ); - } + nssv_constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const nssv_noexcept // (2) + { + return find_first_not_of(basic_string_view(&c, 1), pos); + } - // ends_with(), 3x, since C++20: + nssv_constexpr size_type find_first_not_of(CharT const* s, size_type pos, size_type count) const // (3) + { + return find_first_not_of(basic_string_view(s, count), pos); + } - nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept // (1) - { - return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0; - } + nssv_constexpr size_type find_first_not_of(CharT const* s, size_type pos = 0) const // (4) + { + return find_first_not_of(basic_string_view(s), pos); + } - nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept // (2) - { - return ends_with( basic_string_view( &c, 1 ) ); - } + // find_last_not_of(), 4x: - nssv_constexpr bool ends_with( CharT const * s ) const // (3) - { - return ends_with( basic_string_view( s ) ); - } + nssv_constexpr size_type find_last_not_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) + { + return empty() ? npos + : pos >= size() ? find_last_not_of(v, size() - 1) + : to_pos(std::find_if(const_reverse_iterator(cbegin() + pos + 1), crend(), not_in_view(v))); + } - // find(), 4x: + nssv_constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const nssv_noexcept // (2) + { + return find_last_not_of(basic_string_view(&c, 1), pos); + } - nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) - { - return assert( v.size() == 0 || v.data() != nssv_nullptr ) - , pos >= size() - ? npos - : to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); - } + nssv_constexpr size_type find_last_not_of(CharT const* s, size_type pos, size_type count) const // (3) + { + return find_last_not_of(basic_string_view(s, count), pos); + } - nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) - { - return find( basic_string_view( &c, 1 ), pos ); - } + nssv_constexpr size_type find_last_not_of(CharT const* s, size_type pos = npos) const // (4) + { + return find_last_not_of(basic_string_view(s), pos); + } - nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const // (3) - { - return find( basic_string_view( s, n ), pos ); - } + // Constants: - nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const // (4) - { - return find( basic_string_view( s ), pos ); - } +#if nssv_CPP17_OR_GREATER + static nssv_constexpr size_type npos = size_type(-1); +#elif nssv_CPP11_OR_GREATER + enum : size_type + { + npos = size_type(-1) + }; +#else + enum + { + npos = size_type(-1) + }; +#endif - // rfind(), 4x: + private: + struct not_in_view + { + const basic_string_view v; - nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) - { - if ( size() < v.size() ) - return npos; + nssv_constexpr not_in_view(basic_string_view v) + : v(v) + { + } - if ( v.empty() ) - return (std::min)( size(), pos ); + nssv_constexpr bool operator()(CharT c) const + { + return npos == v.find_first_of(c); + } + }; - const_iterator last = cbegin() + (std::min)( size() - v.size(), pos ) + v.size(); - const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq ); + nssv_constexpr size_type to_pos(const_iterator it) const + { + return it == cend() ? npos : size_type(it - cbegin()); + } - return result != last ? size_type( result - cbegin() ) : npos; - } + nssv_constexpr size_type to_pos(const_reverse_iterator it) const + { + return it == crend() ? npos : size_type(crend() - it - 1); + } - nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept // (2) - { - return rfind( basic_string_view( &c, 1 ), pos ); - } + nssv_constexpr const_reference data_at(size_type pos) const + { +#if nssv_BETWEEN(nssv_COMPILER_GNUC_VERSION, 1, 500) + return data_[pos]; +#else + return assert(pos < size()), data_[pos]; +#endif + } - nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const // (3) - { - return rfind( basic_string_view( s, n ), pos ); - } + private: + const_pointer data_; + size_type size_; - nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const // (4) - { - return rfind( basic_string_view( s ), pos ); - } + public: +#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS - // find_first_of(), 4x: + template + basic_string_view(std::basic_string const& s) nssv_noexcept + : data_(s.data()) + , size_(s.size()) + { + } - nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) - { - return pos >= size() - ? npos - : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); - } +#if nssv_HAVE_EXPLICIT_CONVERSION - nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) - { - return find_first_of( basic_string_view( &c, 1 ), pos ); - } + template + explicit operator std::basic_string() const + { + return to_string(Allocator()); + } - nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const // (3) - { - return find_first_of( basic_string_view( s, n ), pos ); - } +#endif // nssv_HAVE_EXPLICIT_CONVERSION - nssv_constexpr size_type find_first_of( CharT const * s, size_type pos = 0 ) const // (4) - { - return find_first_of( basic_string_view( s ), pos ); - } +#if nssv_CPP11_OR_GREATER - // find_last_of(), 4x: + template> + std::basic_string to_string(Allocator const& a = Allocator()) const + { + return std::basic_string(begin(), end(), a); + } - nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) - { - return empty() - ? npos - : pos >= size() - ? find_last_of( v, size() - 1 ) - : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) ); - } +#else - nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) - { - return find_last_of( basic_string_view( &c, 1 ), pos ); - } + std::basic_string to_string() const + { + return std::basic_string(begin(), end()); + } - nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const // (3) - { - return find_last_of( basic_string_view( s, count ), pos ); - } + template + std::basic_string to_string(Allocator const& a) const + { + return std::basic_string(begin(), end(), a); + } - nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const // (4) - { - return find_last_of( basic_string_view( s ), pos ); - } +#endif // nssv_CPP11_OR_GREATER - // find_first_not_of(), 4x: +#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS + }; - nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) - { - return pos >= size() - ? npos - : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) ); - } + // + // Non-member functions: + // - nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) - { - return find_first_not_of( basic_string_view( &c, 1 ), pos ); - } + // 24.4.3 Non-member comparison functions: + // lexicographically compare two string views (function template): - nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const // (3) - { - return find_first_not_of( basic_string_view( s, count ), pos ); - } + template + nssv_constexpr bool operator==(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) == 0; + } - nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const // (4) - { - return find_first_not_of( basic_string_view( s ), pos ); - } + template + nssv_constexpr bool operator!=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) != 0; + } - // find_last_not_of(), 4x: + template + nssv_constexpr bool operator<(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) < 0; + } - nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) - { - return empty() - ? npos - : pos >= size() - ? find_last_not_of( v, size() - 1 ) - : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) ); - } + template + nssv_constexpr bool operator<=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) <= 0; + } - nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) - { - return find_last_not_of( basic_string_view( &c, 1 ), pos ); - } + template + nssv_constexpr bool operator>(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) > 0; + } - nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const // (3) - { - return find_last_not_of( basic_string_view( s, count ), pos ); - } + template + nssv_constexpr bool operator>=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) >= 0; + } - nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const // (4) - { - return find_last_not_of( basic_string_view( s ), pos ); - } + // Let S be basic_string_view, and sv be an instance of S. + // Implementations shall provide sufficient additional overloads marked + // constexpr and noexcept so that an object t with an implicit conversion + // to S can be compared according to Table 67. - // Constants: +#if nssv_CPP11_OR_GREATER && !nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 100, 141) -#if nssv_CPP17_OR_GREATER - static nssv_constexpr size_type npos = size_type(-1); -#elif nssv_CPP11_OR_GREATER - enum : size_type { npos = size_type(-1) }; +#define nssv_BASIC_STRING_VIEW_I(T, U) typename std::decay>::type + +#if nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 140, 150) +#define nssv_MSVC_ORDER(x) , int = x #else - enum { npos = size_type(-1) }; +#define nssv_MSVC_ORDER(x) /*, int=x*/ #endif -private: - struct not_in_view - { - const basic_string_view v; - - nssv_constexpr not_in_view( basic_string_view v ) : v( v ) {} + // == - nssv_constexpr bool operator()( CharT c ) const + template + nssv_constexpr bool operator==(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept { - return npos == v.find_first_of( c ); + return lhs.compare(rhs) == 0; } - }; - - nssv_constexpr size_type to_pos( const_iterator it ) const - { - return it == cend() ? npos : size_type( it - cbegin() ); - } - nssv_constexpr size_type to_pos( const_reverse_iterator it ) const - { - return it == crend() ? npos : size_type( crend() - it - 1 ); - } - - nssv_constexpr const_reference data_at( size_type pos ) const - { -#if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 ) - return data_[pos]; -#else - return assert( pos < size() ), data_[pos]; -#endif - } + template + nssv_constexpr bool operator==(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; + } -private: - const_pointer data_; - size_type size_; + // != -public: -#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS + template + nssv_constexpr bool operator!=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept + { + return lhs.size() != rhs.size() || lhs.compare(rhs) != 0; + } - template< class Allocator > - basic_string_view( std::basic_string const & s ) nssv_noexcept - : data_( s.data() ) - , size_( s.size() ) - {} + template + nssv_constexpr bool operator!=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) != 0; + } -#if nssv_HAVE_EXPLICIT_CONVERSION + // < - template< class Allocator > - explicit operator std::basic_string() const - { - return to_string( Allocator() ); - } + template + nssv_constexpr bool operator<(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept + { + return lhs.compare(rhs) < 0; + } -#endif // nssv_HAVE_EXPLICIT_CONVERSION + template + nssv_constexpr bool operator<(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) < 0; + } -#if nssv_CPP11_OR_GREATER + // <= - template< class Allocator = std::allocator > - std::basic_string - to_string( Allocator const & a = Allocator() ) const - { - return std::basic_string( begin(), end(), a ); - } + template + nssv_constexpr bool operator<=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept + { + return lhs.compare(rhs) <= 0; + } -#else + template + nssv_constexpr bool operator<=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) <= 0; + } - std::basic_string - to_string() const - { - return std::basic_string( begin(), end() ); - } + // > - template< class Allocator > - std::basic_string - to_string( Allocator const & a ) const - { - return std::basic_string( begin(), end(), a ); - } + template + nssv_constexpr bool operator>(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept + { + return lhs.compare(rhs) > 0; + } -#endif // nssv_CPP11_OR_GREATER + template + nssv_constexpr bool operator>(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) > 0; + } -#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS -}; + // >= -// -// Non-member functions: -// + template + nssv_constexpr bool operator>=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept + { + return lhs.compare(rhs) >= 0; + } -// 24.4.3 Non-member comparison functions: -// lexicographically compare two string views (function template): - -template< class CharT, class Traits > -nssv_constexpr bool operator== ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) == 0 ; } - -template< class CharT, class Traits > -nssv_constexpr bool operator!= ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) != 0 ; } - -template< class CharT, class Traits > -nssv_constexpr bool operator< ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) < 0 ; } - -template< class CharT, class Traits > -nssv_constexpr bool operator<= ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) <= 0 ; } - -template< class CharT, class Traits > -nssv_constexpr bool operator> ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) > 0 ; } - -template< class CharT, class Traits > -nssv_constexpr bool operator>= ( - basic_string_view lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.compare( rhs ) >= 0 ; } - -// Let S be basic_string_view, and sv be an instance of S. -// Implementations shall provide sufficient additional overloads marked -// constexpr and noexcept so that an object t with an implicit conversion -// to S can be compared according to Table 67. - -#if nssv_CPP11_OR_GREATER && ! nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 ) - -#define nssv_BASIC_STRING_VIEW_I(T,U) typename std::decay< basic_string_view >::type - -#if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 ) -# define nssv_MSVC_ORDER(x) , int=x -#else -# define nssv_MSVC_ORDER(x) /*, int=x*/ -#endif - -// == - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator==( - basic_string_view lhs, - nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept -{ return lhs.compare( rhs ) == 0; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator==( - nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, - basic_string_view rhs ) nssv_noexcept -{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; } - -// != - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator!= ( - basic_string_view < CharT, Traits > lhs, - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept -{ return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator!= ( - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, - basic_string_view < CharT, Traits > rhs ) nssv_noexcept -{ return lhs.compare( rhs ) != 0 ; } - -// < - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator< ( - basic_string_view < CharT, Traits > lhs, - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept -{ return lhs.compare( rhs ) < 0 ; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator< ( - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, - basic_string_view < CharT, Traits > rhs ) nssv_noexcept -{ return lhs.compare( rhs ) < 0 ; } - -// <= - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator<= ( - basic_string_view < CharT, Traits > lhs, - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept -{ return lhs.compare( rhs ) <= 0 ; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator<= ( - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, - basic_string_view < CharT, Traits > rhs ) nssv_noexcept -{ return lhs.compare( rhs ) <= 0 ; } - -// > - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator> ( - basic_string_view < CharT, Traits > lhs, - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept -{ return lhs.compare( rhs ) > 0 ; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator> ( - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, - basic_string_view < CharT, Traits > rhs ) nssv_noexcept -{ return lhs.compare( rhs ) > 0 ; } - -// >= - -template< class CharT, class Traits nssv_MSVC_ORDER(1) > -nssv_constexpr bool operator>= ( - basic_string_view < CharT, Traits > lhs, - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept -{ return lhs.compare( rhs ) >= 0 ; } - -template< class CharT, class Traits nssv_MSVC_ORDER(2) > -nssv_constexpr bool operator>= ( - nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, - basic_string_view < CharT, Traits > rhs ) nssv_noexcept -{ return lhs.compare( rhs ) >= 0 ; } + template + nssv_constexpr bool operator>=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + { + return lhs.compare(rhs) >= 0; + } #undef nssv_MSVC_ORDER #undef nssv_BASIC_STRING_VIEW_I #endif // nssv_CPP11_OR_GREATER -// 24.4.4 Inserters and extractors: + // 24.4.4 Inserters and extractors: -namespace detail { + namespace detail + { -template< class Stream > -void write_padding( Stream & os, std::streamsize n ) -{ - for ( std::streamsize i = 0; i < n; ++i ) - os.rdbuf()->sputc( os.fill() ); -} + template + void write_padding(Stream& os, std::streamsize n) + { + for (std::streamsize i = 0; i < n; ++i) + os.rdbuf()->sputc(os.fill()); + } -template< class Stream, class View > -Stream & write_to_stream( Stream & os, View const & sv ) -{ - typename Stream::sentry sentry( os ); + template + Stream& write_to_stream(Stream& os, View const& sv) + { + typename Stream::sentry sentry(os); - if ( !os ) - return os; + if (!os) + return os; - const std::streamsize length = static_cast( sv.length() ); + const std::streamsize length = static_cast(sv.length()); - // Whether, and how, to pad: - const bool pad = ( length < os.width() ); - const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; + // Whether, and how, to pad: + const bool pad = (length < os.width()); + const bool left_pad = pad && (os.flags() & std::ios_base::adjustfield) == std::ios_base::right; - if ( left_pad ) - write_padding( os, os.width() - length ); + if (left_pad) + write_padding(os, os.width() - length); - // Write span characters: - os.rdbuf()->sputn( sv.begin(), length ); + // Write span characters: + os.rdbuf()->sputn(sv.begin(), length); - if ( pad && !left_pad ) - write_padding( os, os.width() - length ); + if (pad && !left_pad) + write_padding(os, os.width() - length); - // Reset output stream width: - os.width( 0 ); + // Reset output stream width: + os.width(0); - return os; -} + return os; + } -} // namespace detail + } // namespace detail -template< class CharT, class Traits > -std::basic_ostream & -operator<<( - std::basic_ostream& os, - basic_string_view sv ) -{ - return detail::write_to_stream( os, sv ); -} + template + std::basic_ostream& operator<<(std::basic_ostream& os, basic_string_view sv) + { + return detail::write_to_stream(os, sv); + } -// Several typedefs for common character types are provided: + // Several typedefs for common character types are provided: -typedef basic_string_view string_view; -typedef basic_string_view wstring_view; + typedef basic_string_view string_view; + typedef basic_string_view wstring_view; #if nssv_HAVE_WCHAR16_T -typedef basic_string_view u16string_view; -typedef basic_string_view u32string_view; + typedef basic_string_view u16string_view; + typedef basic_string_view u32string_view; #endif -}} // namespace nonstd::sv_lite + } // namespace sv_lite +} // namespace nonstd::sv_lite // // 24.4.6 Suffix for basic_string_view literals: @@ -2965,59 +3119,63 @@ typedef basic_string_view u32string_view; #if nssv_HAVE_USER_DEFINED_LITERALS -namespace nonstd { -nssv_inline_ns namespace literals { -nssv_inline_ns namespace string_view_literals { +namespace nonstd +{ + nssv_inline_ns namespace literals + { + nssv_inline_ns namespace string_view_literals + { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS -nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) -{ - return nonstd::sv_lite::string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::string_view operator"" sv(const char* str, size_t len) nssv_noexcept // (1) + { + return nonstd::sv_lite::string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) -{ - return nonstd::sv_lite::u16string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::u16string_view operator"" sv(const char16_t* str, size_t len) nssv_noexcept // (2) + { + return nonstd::sv_lite::u16string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) -{ - return nonstd::sv_lite::u32string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::u32string_view operator"" sv(const char32_t* str, size_t len) nssv_noexcept // (3) + { + return nonstd::sv_lite::u32string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) -{ - return nonstd::sv_lite::wstring_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::wstring_view operator"" sv(const wchar_t* str, size_t len) nssv_noexcept // (4) + { + return nonstd::sv_lite::wstring_view{ str, len }; + } #endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS #if nssv_CONFIG_USR_SV_OPERATOR -nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) -{ - return nonstd::sv_lite::string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::string_view operator"" _sv(const char* str, size_t len) nssv_noexcept // (1) + { + return nonstd::sv_lite::string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) -{ - return nonstd::sv_lite::u16string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::u16string_view operator"" _sv(const char16_t* str, size_t len) nssv_noexcept // (2) + { + return nonstd::sv_lite::u16string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) -{ - return nonstd::sv_lite::u32string_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::u32string_view operator"" _sv(const char32_t* str, size_t len) nssv_noexcept // (3) + { + return nonstd::sv_lite::u32string_view{ str, len }; + } -nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) -{ - return nonstd::sv_lite::wstring_view{ str, len }; -} + nssv_constexpr nonstd::sv_lite::wstring_view operator"" _sv(const wchar_t* str, size_t len) nssv_noexcept // (4) + { + return nonstd::sv_lite::wstring_view{ str, len }; + } #endif // nssv_CONFIG_USR_SV_OPERATOR - -}}} // namespace nonstd::literals::string_view_literals + } + } +} // namespace nonstd #endif @@ -3027,46 +3185,45 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd { -namespace sv_lite { +namespace nonstd +{ + namespace sv_lite + { -// Exclude MSVC 14 (19.00): it yields ambiguous to_string(): + // Exclude MSVC 14 (19.00): it yields ambiguous to_string(): #if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140 -template< class CharT, class Traits, class Allocator = std::allocator > -std::basic_string -to_string( basic_string_view v, Allocator const & a = Allocator() ) -{ - return std::basic_string( v.begin(), v.end(), a ); -} + template> + std::basic_string to_string(basic_string_view v, Allocator const& a = Allocator()) + { + return std::basic_string(v.begin(), v.end(), a); + } #else -template< class CharT, class Traits > -std::basic_string -to_string( basic_string_view v ) -{ - return std::basic_string( v.begin(), v.end() ); -} + template + std::basic_string to_string(basic_string_view v) + { + return std::basic_string(v.begin(), v.end()); + } -template< class CharT, class Traits, class Allocator > -std::basic_string -to_string( basic_string_view v, Allocator const & a ) -{ - return std::basic_string( v.begin(), v.end(), a ); -} + template + std::basic_string to_string(basic_string_view v, Allocator const& a) + { + return std::basic_string(v.begin(), v.end(), a); + } #endif // nssv_CPP11_OR_GREATER -template< class CharT, class Traits, class Allocator > -basic_string_view -to_string_view( std::basic_string const & s ) -{ - return basic_string_view( s.data(), s.size() ); -} + template + basic_string_view to_string_view(std::basic_string const& s) + { + return basic_string_view(s.data(), s.size()); + } -}} // namespace nonstd::sv_lite + } // namespace sv_lite +} // namespace nonstd #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS @@ -3074,33 +3231,34 @@ to_string_view( std::basic_string const & s ) // make types and algorithms available in namespace nonstd: // -namespace nonstd { +namespace nonstd +{ -using sv_lite::basic_string_view; -using sv_lite::string_view; -using sv_lite::wstring_view; + using sv_lite::basic_string_view; + using sv_lite::string_view; + using sv_lite::wstring_view; #if nssv_HAVE_WCHAR16_T -using sv_lite::u16string_view; + using sv_lite::u16string_view; #endif #if nssv_HAVE_WCHAR32_T -using sv_lite::u32string_view; + using sv_lite::u32string_view; #endif -// literal "sv" + // literal "sv" -using sv_lite::operator==; -using sv_lite::operator!=; -using sv_lite::operator<; -using sv_lite::operator<=; -using sv_lite::operator>; -using sv_lite::operator>=; + using sv_lite::operator==; + using sv_lite::operator!=; + using sv_lite::operator<; + using sv_lite::operator<=; + using sv_lite::operator>; + using sv_lite::operator>=; -using sv_lite::operator<<; + using sv_lite::operator<<; #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -using sv_lite::to_string; -using sv_lite::to_string_view; + using sv_lite::to_string; + using sv_lite::to_string_view; #endif } // namespace nonstd @@ -3114,47 +3272,48 @@ using sv_lite::to_string_view; #include -namespace std { - -template<> -struct hash< nonstd::string_view > +namespace std { -public: - std::size_t operator()( nonstd::string_view v ) const nssv_noexcept + + template<> + struct hash { - return std::hash()( std::string( v.data(), v.size() ) ); - } -}; + public: + std::size_t operator()(nonstd::string_view v) const nssv_noexcept + { + return std::hash()(std::string(v.data(), v.size())); + } + }; -template<> -struct hash< nonstd::wstring_view > -{ -public: - std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept + template<> + struct hash { - return std::hash()( std::wstring( v.data(), v.size() ) ); - } -}; + public: + std::size_t operator()(nonstd::wstring_view v) const nssv_noexcept + { + return std::hash()(std::wstring(v.data(), v.size())); + } + }; -template<> -struct hash< nonstd::u16string_view > -{ -public: - std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept + template<> + struct hash { - return std::hash()( std::u16string( v.data(), v.size() ) ); - } -}; + public: + std::size_t operator()(nonstd::u16string_view v) const nssv_noexcept + { + return std::hash()(std::u16string(v.data(), v.size())); + } + }; -template<> -struct hash< nonstd::u32string_view > -{ -public: - std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept + template<> + struct hash { - return std::hash()( std::u32string( v.data(), v.size() ) ); - } -}; + public: + std::size_t operator()(nonstd::u32string_view v) const nssv_noexcept + { + return std::hash()(std::u32string(v.data(), v.size())); + } + }; } // namespace std @@ -3165,10 +3324,9 @@ nssv_RESTORE_WARNINGS() #endif // nssv_HAVE_STD_STRING_VIEW #endif // NONSTD_SV_LITE_H_INCLUDED - - // If there is another version of Hedley, then the newer one - // takes precedence. - // See: https://github.com/nemequ/hedley +// If there is another version of Hedley, then the newer one +// takes precedence. +// See: https://github.com/nemequ/hedley /* Hedley - https://nemequ.github.io/hedley * Created by Evan Nemerson * @@ -3183,1500 +3341,1338 @@ nssv_RESTORE_WARNINGS() #if !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < 9) #if defined(HEDLEY_VERSION) -# undef HEDLEY_VERSION +#undef HEDLEY_VERSION #endif #define HEDLEY_VERSION 9 #if defined(HEDLEY_STRINGIFY_EX) -# undef HEDLEY_STRINGIFY_EX +#undef HEDLEY_STRINGIFY_EX #endif #define HEDLEY_STRINGIFY_EX(x) #x #if defined(HEDLEY_STRINGIFY) -# undef HEDLEY_STRINGIFY +#undef HEDLEY_STRINGIFY #endif #define HEDLEY_STRINGIFY(x) HEDLEY_STRINGIFY_EX(x) #if defined(HEDLEY_CONCAT_EX) -# undef HEDLEY_CONCAT_EX +#undef HEDLEY_CONCAT_EX #endif -#define HEDLEY_CONCAT_EX(a,b) a##b +#define HEDLEY_CONCAT_EX(a, b) a##b #if defined(HEDLEY_CONCAT) -# undef HEDLEY_CONCAT +#undef HEDLEY_CONCAT #endif -#define HEDLEY_CONCAT(a,b) HEDLEY_CONCAT_EX(a,b) +#define HEDLEY_CONCAT(a, b) HEDLEY_CONCAT_EX(a, b) #if defined(HEDLEY_VERSION_ENCODE) -# undef HEDLEY_VERSION_ENCODE +#undef HEDLEY_VERSION_ENCODE #endif -#define HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) +#define HEDLEY_VERSION_ENCODE(major, minor, revision) (((major)*1000000) + ((minor)*1000) + (revision)) #if defined(HEDLEY_VERSION_DECODE_MAJOR) -# undef HEDLEY_VERSION_DECODE_MAJOR +#undef HEDLEY_VERSION_DECODE_MAJOR #endif #define HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(HEDLEY_VERSION_DECODE_MINOR) -# undef HEDLEY_VERSION_DECODE_MINOR +#undef HEDLEY_VERSION_DECODE_MINOR #endif #define HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(HEDLEY_VERSION_DECODE_REVISION) -# undef HEDLEY_VERSION_DECODE_REVISION +#undef HEDLEY_VERSION_DECODE_REVISION #endif #define HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(HEDLEY_GNUC_VERSION) -# undef HEDLEY_GNUC_VERSION +#undef HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) -# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) -# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(HEDLEY_GNUC_VERSION_CHECK) -# undef HEDLEY_GNUC_VERSION_CHECK +#undef HEDLEY_GNUC_VERSION_CHECK #endif #if defined(HEDLEY_GNUC_VERSION) -# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_MSVC_VERSION) -# undef HEDLEY_MSVC_VERSION +#undef HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#define HEDLEY_MSVC_VERSION \ + HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) -# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(HEDLEY_MSVC_VERSION_CHECK) -# undef HEDLEY_MSVC_VERSION_CHECK +#undef HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(_MSC_VER) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else -# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(HEDLEY_INTEL_VERSION) -# undef HEDLEY_INTEL_VERSION +#undef HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) -# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) -# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(HEDLEY_INTEL_VERSION_CHECK) -# undef HEDLEY_INTEL_VERSION_CHECK +#undef HEDLEY_INTEL_VERSION_CHECK #endif #if defined(HEDLEY_INTEL_VERSION) -# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_PGI_VERSION) -# undef HEDLEY_PGI_VERSION +#undef HEDLEY_PGI_VERSION #endif #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) -# define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(HEDLEY_PGI_VERSION_CHECK) -# undef HEDLEY_PGI_VERSION_CHECK +#undef HEDLEY_PGI_VERSION_CHECK #endif #if defined(HEDLEY_PGI_VERSION) -# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_SUNPRO_VERSION) -# undef HEDLEY_SUNPRO_VERSION +#undef HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#define HEDLEY_SUNPRO_VERSION \ + HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ + (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ + (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C)&0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#define HEDLEY_SUNPRO_VERSION \ + HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ + (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ + (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) -# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC)&0xf) #endif #if defined(HEDLEY_SUNPRO_VERSION_CHECK) -# undef HEDLEY_SUNPRO_VERSION_CHECK +#undef HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(HEDLEY_SUNPRO_VERSION) -# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -# undef HEDLEY_EMSCRIPTEN_VERSION +#undef HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) -# define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION_CHECK) -# undef HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_ARM_VERSION) -# undef HEDLEY_ARM_VERSION +#undef HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) -# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#define HEDLEY_ARM_VERSION \ + HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) -# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#define HEDLEY_ARM_VERSION \ + HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) #endif #if defined(HEDLEY_ARM_VERSION_CHECK) -# undef HEDLEY_ARM_VERSION_CHECK +#undef HEDLEY_ARM_VERSION_CHECK #endif #if defined(HEDLEY_ARM_VERSION) -# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_IBM_VERSION) -# undef HEDLEY_IBM_VERSION +#undef HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) -# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(HEDLEY_IBM_VERSION_CHECK) -# undef HEDLEY_IBM_VERSION_CHECK +#undef HEDLEY_IBM_VERSION_CHECK #endif #if defined(HEDLEY_IBM_VERSION) -# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TI_VERSION) -# undef HEDLEY_TI_VERSION +#undef HEDLEY_TI_VERSION #endif #if defined(__TI_COMPILER_VERSION__) -# define HEDLEY_TI_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define HEDLEY_TI_VERSION \ + HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_VERSION_CHECK) -# undef HEDLEY_TI_VERSION_CHECK +#undef HEDLEY_TI_VERSION_CHECK #endif #if defined(HEDLEY_TI_VERSION) -# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_CRAY_VERSION) -# undef HEDLEY_CRAY_VERSION +#undef HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) -# if defined(_RELEASE_PATCHLEVEL) -# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) -# else -# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) -# endif +#if defined(_RELEASE_PATCHLEVEL) +#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) +#else +#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +#endif #endif #if defined(HEDLEY_CRAY_VERSION_CHECK) -# undef HEDLEY_CRAY_VERSION_CHECK +#undef HEDLEY_CRAY_VERSION_CHECK #endif #if defined(HEDLEY_CRAY_VERSION) -# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_IAR_VERSION) -# undef HEDLEY_IAR_VERSION +#undef HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) -# if __VER__ > 1000 -# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) -# else -# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) -# endif +#if __VER__ > 1000 +#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) +#else +#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) +#endif #endif #if defined(HEDLEY_IAR_VERSION_CHECK) -# undef HEDLEY_IAR_VERSION_CHECK +#undef HEDLEY_IAR_VERSION_CHECK #endif #if defined(HEDLEY_IAR_VERSION) -# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_TINYC_VERSION) -# undef HEDLEY_TINYC_VERSION +#undef HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) -# define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) #endif #if defined(HEDLEY_TINYC_VERSION_CHECK) -# undef HEDLEY_TINYC_VERSION_CHECK +#undef HEDLEY_TINYC_VERSION_CHECK #endif #if defined(HEDLEY_TINYC_VERSION) -# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_DMC_VERSION) -# undef HEDLEY_DMC_VERSION +#undef HEDLEY_DMC_VERSION #endif #if defined(__DMC__) -# define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(HEDLEY_DMC_VERSION_CHECK) -# undef HEDLEY_DMC_VERSION_CHECK +#undef HEDLEY_DMC_VERSION_CHECK #endif #if defined(HEDLEY_DMC_VERSION) -# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_COMPCERT_VERSION) -# undef HEDLEY_COMPCERT_VERSION +#undef HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) -# define HEDLEY_COMPCERT_VERSION HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#define HEDLEY_COMPCERT_VERSION \ + HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) #endif #if defined(HEDLEY_COMPCERT_VERSION_CHECK) -# undef HEDLEY_COMPCERT_VERSION_CHECK +#undef HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(HEDLEY_COMPCERT_VERSION) -# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_PELLES_VERSION) -# undef HEDLEY_PELLES_VERSION +#undef HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) -# define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(HEDLEY_PELLES_VERSION_CHECK) -# undef HEDLEY_PELLES_VERSION_CHECK +#undef HEDLEY_PELLES_VERSION_CHECK #endif #if defined(HEDLEY_PELLES_VERSION) -# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_GCC_VERSION) -# undef HEDLEY_GCC_VERSION +#undef HEDLEY_GCC_VERSION #endif -#if \ - defined(HEDLEY_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(HEDLEY_INTEL_VERSION) && \ - !defined(HEDLEY_PGI_VERSION) && \ - !defined(HEDLEY_ARM_VERSION) && \ - !defined(HEDLEY_TI_VERSION) && \ - !defined(__COMPCERT__) -# define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION +#if defined(HEDLEY_GNUC_VERSION) && !defined(__clang__) && !defined(HEDLEY_INTEL_VERSION) && !defined(HEDLEY_PGI_VERSION) && \ + !defined(HEDLEY_ARM_VERSION) && !defined(HEDLEY_TI_VERSION) && !defined(__COMPCERT__) +#define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION #endif #if defined(HEDLEY_GCC_VERSION_CHECK) -# undef HEDLEY_GCC_VERSION_CHECK +#undef HEDLEY_GCC_VERSION_CHECK #endif #if defined(HEDLEY_GCC_VERSION) -# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(HEDLEY_HAS_ATTRIBUTE) -# undef HEDLEY_HAS_ATTRIBUTE +#undef HEDLEY_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -# define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else -# define HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) __has_attribute(attribute) #else -# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_ATTRIBUTE +#undef HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) __has_attribute(attribute) #else -# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_HAS_CPP_ATTRIBUTE +#undef HEDLEY_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else -# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) #else -# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) #else -# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_BUILTIN) -# undef HEDLEY_HAS_BUILTIN +#undef HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else -# define HEDLEY_HAS_BUILTIN(builtin) (0) +#define HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(HEDLEY_GNUC_HAS_BUILTIN) -# undef HEDLEY_GNUC_HAS_BUILTIN +#undef HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) #else -# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_BUILTIN) -# undef HEDLEY_GCC_HAS_BUILTIN +#undef HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) -# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) #else -# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_FEATURE) -# undef HEDLEY_HAS_FEATURE +#undef HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else -# define HEDLEY_HAS_FEATURE(feature) (0) +#define HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(HEDLEY_GNUC_HAS_FEATURE) -# undef HEDLEY_GNUC_HAS_FEATURE +#undef HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) #else -# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_FEATURE) -# undef HEDLEY_GCC_HAS_FEATURE +#undef HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) -# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) #else -# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_EXTENSION) -# undef HEDLEY_HAS_EXTENSION +#undef HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else -# define HEDLEY_HAS_EXTENSION(extension) (0) +#define HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(HEDLEY_GNUC_HAS_EXTENSION) -# undef HEDLEY_GNUC_HAS_EXTENSION +#undef HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) #else -# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_EXTENSION) -# undef HEDLEY_GCC_HAS_EXTENSION +#undef HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) -# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) #else -# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) #else -# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) #else -# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) #else -# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_HAS_WARNING) -# undef HEDLEY_HAS_WARNING +#undef HEDLEY_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#define HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else -# define HEDLEY_HAS_WARNING(warning) (0) +#define HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(HEDLEY_GNUC_HAS_WARNING) -# undef HEDLEY_GNUC_HAS_WARNING +#undef HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) #else -# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_GCC_HAS_WARNING) -# undef HEDLEY_GCC_HAS_WARNING +#undef HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) -# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) #else -# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_TI_VERSION_CHECK(6,0,0) || \ - HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ - HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ - HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ - (HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) -# define HEDLEY_PRAGMA(value) _Pragma(#value) -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_PRAGMA(value) __pragma(value) +#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__clang__) || HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_VERSION_CHECK(6, 0, 0) || HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) || \ + HEDLEY_TINYC_VERSION_CHECK(0, 9, 17) || HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ + (HEDLEY_IBM_VERSION_CHECK(10, 1, 0) && defined(__C99_PRAGMA_OPERATOR)) +#define HEDLEY_PRAGMA(value) _Pragma(#value) +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_PRAGMA(value) __pragma(value) #else -# define HEDLEY_PRAGMA(value) +#define HEDLEY_PRAGMA(value) #endif #if defined(HEDLEY_DIAGNOSTIC_PUSH) -# undef HEDLEY_DIAGNOSTIC_PUSH +#undef HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(HEDLEY_DIAGNOSTIC_POP) -# undef HEDLEY_DIAGNOSTIC_POP +#undef HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif HEDLEY_GCC_VERSION_CHECK(4,6,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) -# define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif HEDLEY_ARM_VERSION_CHECK(5,6,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif HEDLEY_TI_VERSION_CHECK(8,1,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) -# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) +#define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif HEDLEY_ARM_VERSION_CHECK(5, 6, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif HEDLEY_TI_VERSION_CHECK(8, 1, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #else -# define HEDLEY_DIAGNOSTIC_PUSH -# define HEDLEY_DIAGNOSTIC_POP +#define HEDLEY_DIAGNOSTIC_PUSH +#define HEDLEY_DIAGNOSTIC_POP #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) -# undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if HEDLEY_HAS_WARNING("-Wdeprecated-declarations") -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif HEDLEY_TI_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable : 4996)) +#elif HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else -# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) -# undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif HEDLEY_TI_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable : 4068)) +#elif HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") #else -# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) -# undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if HEDLEY_HAS_WARNING("-Wcast-qual") -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif HEDLEY_GCC_VERSION_CHECK(3,0,0) -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif HEDLEY_GCC_VERSION_CHECK(3, 0, 0) +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else -# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(HEDLEY_DEPRECATED) -# undef HEDLEY_DEPRECATED +#undef HEDLEY_DEPRECATED #endif #if defined(HEDLEY_DEPRECATED_FOR) -# undef HEDLEY_DEPRECATED_FOR +#undef HEDLEY_DEPRECATED_FOR #endif #if defined(__cplusplus) && (__cplusplus >= 201402L) -# define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] -# define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] -#elif \ - HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ - HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ - HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - HEDLEY_TI_VERSION_CHECK(8,3,0) -# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif \ - HEDLEY_HAS_ATTRIBUTE(deprecated) || \ - HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0) -# define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ - HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - HEDLEY_PELLES_VERSION_CHECK(6,50,0) -# define HEDLEY_DEPRECATED(since) _declspec(deprecated) -# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_DEPRECATED(since) _Pragma("deprecated") -# define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] +#define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] +#elif HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) || \ + HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || HEDLEY_TI_VERSION_CHECK(8, 3, 0) +#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif HEDLEY_HAS_ATTRIBUTE(deprecated) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) +#define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " #since)) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_PELLES_VERSION_CHECK(6, 50, 0) +#define HEDLEY_DEPRECATED(since) _declspec(deprecated) +#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_DEPRECATED(since) _Pragma("deprecated") +#define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") #else -# define HEDLEY_DEPRECATED(since) -# define HEDLEY_DEPRECATED_FOR(since, replacement) +#define HEDLEY_DEPRECATED(since) +#define HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(HEDLEY_UNAVAILABLE) -# undef HEDLEY_UNAVAILABLE +#undef HEDLEY_UNAVAILABLE #endif -#if \ - HEDLEY_HAS_ATTRIBUTE(warning) || \ - HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#if HEDLEY_HAS_ATTRIBUTE(warning) || HEDLEY_GCC_VERSION_CHECK(4, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else -# define HEDLEY_UNAVAILABLE(available_since) +#define HEDLEY_UNAVAILABLE(available_since) #endif #if defined(HEDLEY_WARN_UNUSED_RESULT) -# undef HEDLEY_WARN_UNUSED_RESULT +#undef HEDLEY_WARN_UNUSED_RESULT #endif #if defined(__cplusplus) && (__cplusplus >= 201703L) -# define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] -#elif \ - HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ - HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] +#elif HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ -# define HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#define HEDLEY_WARN_UNUSED_RESULT _Check_return_ #else -# define HEDLEY_WARN_UNUSED_RESULT +#define HEDLEY_WARN_UNUSED_RESULT #endif #if defined(HEDLEY_SENTINEL) -# undef HEDLEY_SENTINEL -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(sentinel) || \ - HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(5,4,0) -# define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#undef HEDLEY_SENTINEL +#endif +#if HEDLEY_HAS_ATTRIBUTE(sentinel) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(5, 4, 0) +#define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else -# define HEDLEY_SENTINEL(position) +#define HEDLEY_SENTINEL(position) #endif #if defined(HEDLEY_NO_RETURN) -# undef HEDLEY_NO_RETURN +#undef HEDLEY_NO_RETURN #endif -#if HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_NO_RETURN __noreturn -#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#if HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_NO_RETURN __noreturn +#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define HEDLEY_NO_RETURN _Noreturn +#define HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) -# define HEDLEY_NO_RETURN [[noreturn]] -#elif \ - HEDLEY_HAS_ATTRIBUTE(noreturn) || \ - HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(18,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) -# define HEDLEY_NO_RETURN __declspec(noreturn) -#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) -# define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) -# define HEDLEY_NO_RETURN __attribute((noreturn)) -#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) -# define HEDLEY_NO_RETURN __declspec(noreturn) +#define HEDLEY_NO_RETURN [[noreturn]] +#elif HEDLEY_HAS_ATTRIBUTE(noreturn) || HEDLEY_GCC_VERSION_CHECK(3, 2, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(18, 0, 0) || \ + (HEDLEY_TI_VERSION_CHECK(17, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define HEDLEY_NO_RETURN __declspec(noreturn) +#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define HEDLEY_NO_RETURN __attribute((noreturn)) +#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define HEDLEY_NO_RETURN __declspec(noreturn) #else -# define HEDLEY_NO_RETURN +#define HEDLEY_NO_RETURN #endif #if defined(HEDLEY_UNREACHABLE) -# undef HEDLEY_UNREACHABLE +#undef HEDLEY_UNREACHABLE #endif #if defined(HEDLEY_UNREACHABLE_RETURN) -# undef HEDLEY_UNREACHABLE_RETURN -#endif -#if \ - (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || \ - HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_IBM_VERSION_CHECK(13,1,5) -# define HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) -# define HEDLEY_UNREACHABLE() __assume(0) -#elif HEDLEY_TI_VERSION_CHECK(6,0,0) -# if defined(__cplusplus) -# define HEDLEY_UNREACHABLE() std::_nassert(0) -# else -# define HEDLEY_UNREACHABLE() _nassert(0) -# endif -# define HEDLEY_UNREACHABLE_RETURN(value) return value +#undef HEDLEY_UNREACHABLE_RETURN +#endif +#if (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 5) +#define HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define HEDLEY_UNREACHABLE() __assume(0) +#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) +#if defined(__cplusplus) +#define HEDLEY_UNREACHABLE() std::_nassert(0) +#else +#define HEDLEY_UNREACHABLE() _nassert(0) +#endif +#define HEDLEY_UNREACHABLE_RETURN(value) return value #elif defined(EXIT_FAILURE) -# define HEDLEY_UNREACHABLE() abort() +#define HEDLEY_UNREACHABLE() abort() #else -# define HEDLEY_UNREACHABLE() -# define HEDLEY_UNREACHABLE_RETURN(value) return value +#define HEDLEY_UNREACHABLE() +#define HEDLEY_UNREACHABLE_RETURN(value) return value #endif #if !defined(HEDLEY_UNREACHABLE_RETURN) -# define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() +#define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() #endif #if defined(HEDLEY_ASSUME) -# undef HEDLEY_ASSUME +#undef HEDLEY_ASSUME #endif -#if \ - HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_ASSUME(expr) __assume(expr) +#if HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_ASSUME(expr) __assume(expr) #elif HEDLEY_HAS_BUILTIN(__builtin_assume) -# define HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif HEDLEY_TI_VERSION_CHECK(6,0,0) -# if defined(__cplusplus) -# define HEDLEY_ASSUME(expr) std::_nassert(expr) -# else -# define HEDLEY_ASSUME(expr) _nassert(expr) -# endif -#elif \ - (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(HEDLEY_ARM_VERSION)) || \ - HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_IBM_VERSION_CHECK(13,1,5) -# define HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#define HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) +#if defined(__cplusplus) +#define HEDLEY_ASSUME(expr) std::_nassert(expr) #else -# define HEDLEY_ASSUME(expr) ((void) (expr)) +#define HEDLEY_ASSUME(expr) _nassert(expr) +#endif +#elif (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(HEDLEY_ARM_VERSION)) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 5) +#define HEDLEY_ASSUME(expr) ((void)((expr) ? 1 : (__builtin_unreachable(), 1))) +#else +#define HEDLEY_ASSUME(expr) ((void)(expr)) #endif - HEDLEY_DIAGNOSTIC_PUSH -#if \ - HEDLEY_HAS_WARNING("-Wvariadic-macros") || \ - HEDLEY_GCC_VERSION_CHECK(4,0,0) -# if defined(__clang__) -# pragma clang diagnostic ignored "-Wvariadic-macros" -# elif defined(HEDLEY_GCC_VERSION) -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# endif +#if HEDLEY_HAS_WARNING("-Wvariadic-macros") || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wvariadic-macros" +#elif defined(HEDLEY_GCC_VERSION) +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#endif #endif #if defined(HEDLEY_NON_NULL) -# undef HEDLEY_NON_NULL -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(nonnull) || \ - HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) -# define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#undef HEDLEY_NON_NULL +#endif +#if HEDLEY_HAS_ATTRIBUTE(nonnull) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else -# define HEDLEY_NON_NULL(...) +#define HEDLEY_NON_NULL(...) #endif HEDLEY_DIAGNOSTIC_POP #if defined(HEDLEY_PRINTF_FORMAT) -# undef HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ - HEDLEY_HAS_ATTRIBUTE(format) || \ - HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif HEDLEY_PELLES_VERSION_CHECK(6,0,0) -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#undef HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && !defined(__USE_MINGW_ANSI_STDIO) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && defined(__USE_MINGW_ANSI_STDIO) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif HEDLEY_HAS_ATTRIBUTE(format) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __declspec(vaformat(printf, string_idx, first_to_check)) #else -# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) #endif #if defined(HEDLEY_CONSTEXPR) -# undef HEDLEY_CONSTEXPR +#undef HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) -# if __cplusplus >= 201103L -# define HEDLEY_CONSTEXPR constexpr -# endif +#if __cplusplus >= 201103L +#define HEDLEY_CONSTEXPR constexpr +#endif #endif #if !defined(HEDLEY_CONSTEXPR) -# define HEDLEY_CONSTEXPR +#define HEDLEY_CONSTEXPR #endif #if defined(HEDLEY_PREDICT) -# undef HEDLEY_PREDICT +#undef HEDLEY_PREDICT #endif #if defined(HEDLEY_LIKELY) -# undef HEDLEY_LIKELY +#undef HEDLEY_LIKELY #endif #if defined(HEDLEY_UNLIKELY) -# undef HEDLEY_UNLIKELY +#undef HEDLEY_UNLIKELY #endif #if defined(HEDLEY_UNPREDICTABLE) -# undef HEDLEY_UNPREDICTABLE +#undef HEDLEY_UNPREDICTABLE #endif #if HEDLEY_HAS_BUILTIN(__builtin_unpredictable) -# define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) -#endif -#if \ - HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ - HEDLEY_GCC_VERSION_CHECK(9,0,0) -# define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) -# define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) -# define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) -# define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -# if !defined(HEDLEY_BUILTIN_UNPREDICTABLE) -# define HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) -# endif -#elif \ - HEDLEY_HAS_BUILTIN(__builtin_expect) || \ - HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - HEDLEY_TINYC_VERSION_CHECK(0,9,27) -# define HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) -# define HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -# define HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -# define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || HEDLEY_GCC_VERSION_CHECK(9, 0, 0) +#define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) +#define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) +#define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) +#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#if !defined(HEDLEY_BUILTIN_UNPREDICTABLE) +#define HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif HEDLEY_HAS_BUILTIN(__builtin_expect) || HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(6, 1, 0) || HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) +#define HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void)(expected)), !!(expr))) +#define HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__({ \ + HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +#define HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__({ \ + HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else -# define HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) -# define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define HEDLEY_LIKELY(expr) (!!(expr)) -# define HEDLEY_UNLIKELY(expr) (!!(expr)) +#define HEDLEY_PREDICT(expr, expected, probability) (((void)(expected)), !!(expr)) +#define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +#define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +#define HEDLEY_LIKELY(expr) (!!(expr)) +#define HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(HEDLEY_UNPREDICTABLE) -# define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) +#define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(HEDLEY_MALLOC) -# undef HEDLEY_MALLOC -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(malloc) || \ - HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_MALLOC __attribute__((__malloc__)) +#undef HEDLEY_MALLOC +#endif +#if HEDLEY_HAS_ATTRIBUTE(malloc) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_MALLOC __attribute__((__malloc__)) #elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) -# define HEDLEY_MALLOC __declspec(restrict) +#define HEDLEY_MALLOC __declspec(restrict) #else -# define HEDLEY_MALLOC +#define HEDLEY_MALLOC #endif #if defined(HEDLEY_PURE) -# undef HEDLEY_PURE -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(pure) || \ - HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_PURE __attribute__((__pure__)) -#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) -# define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#undef HEDLEY_PURE +#endif +#if HEDLEY_HAS_ATTRIBUTE(pure) || HEDLEY_GCC_VERSION_CHECK(2, 96, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_PURE __attribute__((__pure__)) +#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else -# define HEDLEY_PURE +#define HEDLEY_PURE #endif #if defined(HEDLEY_CONST) -# undef HEDLEY_CONST -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(const) || \ - HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - HEDLEY_PGI_VERSION_CHECK(17,10,0) -# define HEDLEY_CONST __attribute__((__const__)) +#undef HEDLEY_CONST +#endif +#if HEDLEY_HAS_ATTRIBUTE(const) || HEDLEY_GCC_VERSION_CHECK(2, 5, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define HEDLEY_CONST __attribute__((__const__)) #else -# define HEDLEY_CONST HEDLEY_PURE +#define HEDLEY_CONST HEDLEY_PURE #endif #if defined(HEDLEY_RESTRICT) -# undef HEDLEY_RESTRICT +#undef HEDLEY_RESTRICT #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) -# define HEDLEY_RESTRICT restrict -#elif \ - HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) -# define HEDLEY_RESTRICT __restrict -#elif HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) -# define HEDLEY_RESTRICT _Restrict +#define HEDLEY_RESTRICT restrict +#elif HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) || \ + HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || defined(__clang__) +#define HEDLEY_RESTRICT __restrict +#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) +#define HEDLEY_RESTRICT _Restrict #else -# define HEDLEY_RESTRICT +#define HEDLEY_RESTRICT #endif #if defined(HEDLEY_INLINE) -# undef HEDLEY_INLINE -#endif -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) -# define HEDLEY_INLINE inline -#elif \ - defined(HEDLEY_GCC_VERSION) || \ - HEDLEY_ARM_VERSION_CHECK(6,2,0) -# define HEDLEY_INLINE __inline__ -#elif \ - HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) -# define HEDLEY_INLINE __inline +#undef HEDLEY_INLINE +#endif +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define HEDLEY_INLINE inline +#elif defined(HEDLEY_GCC_VERSION) || HEDLEY_ARM_VERSION_CHECK(6, 2, 0) +#define HEDLEY_INLINE __inline__ +#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define HEDLEY_INLINE __inline #else -# define HEDLEY_INLINE +#define HEDLEY_INLINE #endif #if defined(HEDLEY_ALWAYS_INLINE) -# undef HEDLEY_ALWAYS_INLINE -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE -#elif HEDLEY_MSVC_VERSION_CHECK(12,0,0) -# define HEDLEY_ALWAYS_INLINE __forceinline -#elif HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) -# define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#undef HEDLEY_ALWAYS_INLINE +#endif +#if HEDLEY_HAS_ATTRIBUTE(always_inline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE +#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) +#define HEDLEY_ALWAYS_INLINE __forceinline +#elif HEDLEY_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus) +#define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else -# define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE +#define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE #endif #if defined(HEDLEY_NEVER_INLINE) -# undef HEDLEY_NEVER_INLINE -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(noinline) || \ - HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) -# define HEDLEY_NEVER_INLINE __declspec(noinline) -#elif HEDLEY_PGI_VERSION_CHECK(10,2,0) -# define HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) -# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) -# define HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) -# define HEDLEY_NEVER_INLINE __declspec(noinline) +#undef HEDLEY_NEVER_INLINE +#endif +#if HEDLEY_HAS_ATTRIBUTE(noinline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define HEDLEY_NEVER_INLINE __declspec(noinline) +#elif HEDLEY_PGI_VERSION_CHECK(10, 2, 0) +#define HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define HEDLEY_NEVER_INLINE __declspec(noinline) #else -# define HEDLEY_NEVER_INLINE +#define HEDLEY_NEVER_INLINE #endif #if defined(HEDLEY_PRIVATE) -# undef HEDLEY_PRIVATE +#undef HEDLEY_PRIVATE #endif #if defined(HEDLEY_PUBLIC) -# undef HEDLEY_PUBLIC +#undef HEDLEY_PUBLIC #endif #if defined(HEDLEY_IMPORT) -# undef HEDLEY_IMPORT +#undef HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) -# define HEDLEY_PRIVATE -# define HEDLEY_PUBLIC __declspec(dllexport) -# define HEDLEY_IMPORT __declspec(dllimport) +#define HEDLEY_PRIVATE +#define HEDLEY_PUBLIC __declspec(dllexport) +#define HEDLEY_IMPORT __declspec(dllimport) +#else +#if HEDLEY_HAS_ATTRIBUTE(visibility) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +#define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) #else -# if \ - HEDLEY_HAS_ATTRIBUTE(visibility) || \ - HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -# define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -# define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) -# else -# define HEDLEY_PRIVATE -# define HEDLEY_PUBLIC -# endif -# define HEDLEY_IMPORT extern +#define HEDLEY_PRIVATE +#define HEDLEY_PUBLIC +#endif +#define HEDLEY_IMPORT extern #endif #if defined(HEDLEY_NO_THROW) -# undef HEDLEY_NO_THROW -#endif -#if \ - HEDLEY_HAS_ATTRIBUTE(nothrow) || \ - HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ - HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) -# define HEDLEY_NO_THROW __declspec(nothrow) +#undef HEDLEY_NO_THROW +#endif +#if HEDLEY_HAS_ATTRIBUTE(nothrow) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define HEDLEY_NO_THROW __declspec(nothrow) #else -# define HEDLEY_NO_THROW +#define HEDLEY_NO_THROW #endif #if defined(HEDLEY_FALL_THROUGH) -# undef HEDLEY_FALL_THROUGH -#endif -#if \ - defined(__cplusplus) && \ - (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - !defined(HEDLEY_PGI_VERSION) -# if \ - (__cplusplus >= 201703L) || \ - ((__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) -# define HEDLEY_FALL_THROUGH [[fallthrough]] -# elif (__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) -# define HEDLEY_FALL_THROUGH [[clang::fallthrough]] -# elif (__cplusplus >= 201103L) && HEDLEY_GCC_VERSION_CHECK(7,0,0) -# define HEDLEY_FALL_THROUGH [[gnu::fallthrough]] -# endif +#undef HEDLEY_FALL_THROUGH +#endif +#if defined(__cplusplus) && (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) && !defined(HEDLEY_PGI_VERSION) +#if (__cplusplus >= 201703L) || ((__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) +#define HEDLEY_FALL_THROUGH [[fallthrough]] +#elif (__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) +#define HEDLEY_FALL_THROUGH [[clang::fallthrough]] +#elif (__cplusplus >= 201103L) && HEDLEY_GCC_VERSION_CHECK(7, 0, 0) +#define HEDLEY_FALL_THROUGH [[gnu::fallthrough]] +#endif #endif #if !defined(HEDLEY_FALL_THROUGH) -# if HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(HEDLEY_PGI_VERSION) -# define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -# elif defined(__fallthrough) /* SAL */ -# define HEDLEY_FALL_THROUGH __fallthrough -# else -# define HEDLEY_FALL_THROUGH -# endif +#if HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough, 7, 0, 0) && !defined(HEDLEY_PGI_VERSION) +#define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif defined(__fallthrough) /* SAL */ +#define HEDLEY_FALL_THROUGH __fallthrough +#else +#define HEDLEY_FALL_THROUGH +#endif #endif #if defined(HEDLEY_RETURNS_NON_NULL) -# undef HEDLEY_RETURNS_NON_NULL +#undef HEDLEY_RETURNS_NON_NULL #endif -#if \ - HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - HEDLEY_GCC_VERSION_CHECK(4,9,0) -# define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#if HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || HEDLEY_GCC_VERSION_CHECK(4, 9, 0) +#define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ -# define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else -# define HEDLEY_RETURNS_NON_NULL +#define HEDLEY_RETURNS_NON_NULL #endif #if defined(HEDLEY_ARRAY_PARAM) -# undef HEDLEY_ARRAY_PARAM -#endif -#if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(HEDLEY_PGI_VERSION) && \ - !defined(HEDLEY_TINYC_VERSION) -# define HEDLEY_ARRAY_PARAM(name) (name) +#undef HEDLEY_ARRAY_PARAM +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ + !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_TINYC_VERSION) +#define HEDLEY_ARRAY_PARAM(name) (name) #else -# define HEDLEY_ARRAY_PARAM(name) +#define HEDLEY_ARRAY_PARAM(name) #endif #if defined(HEDLEY_IS_CONSTANT) -# undef HEDLEY_IS_CONSTANT +#undef HEDLEY_IS_CONSTANT #endif #if defined(HEDLEY_REQUIRE_CONSTEXPR) -# undef HEDLEY_REQUIRE_CONSTEXPR +#undef HEDLEY_REQUIRE_CONSTEXPR #endif /* Note the double-underscore. For internal use only; no API * guarantees! */ #if defined(HEDLEY__IS_CONSTEXPR) -# undef HEDLEY__IS_CONSTEXPR +#undef HEDLEY__IS_CONSTEXPR #endif -#if \ - HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ - HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ - HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \ - HEDLEY_CRAY_VERSION_CHECK(8,1,0) -# define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#if HEDLEY_HAS_BUILTIN(__builtin_constant_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_TINYC_VERSION_CHECK(0, 9, 19) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + HEDLEY_TI_VERSION_CHECK(6, 1, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) || HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) +#define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) -# if \ - HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ - HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - HEDLEY_TINYC_VERSION_CHECK(0,9,24) -# if defined(__INTPTR_TYPE__) -# define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) -# else -# include -# define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -# endif -# elif \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && !defined(HEDLEY_PGI_VERSION)) || \ - HEDLEY_HAS_EXTENSION(c_generic_selections) || \ - HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ - HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - HEDLEY_ARM_VERSION_CHECK(5,3,0) -# if defined(__INTPTR_TYPE__) -# define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) -# else -# include -# define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -# endif -# elif \ - defined(HEDLEY_GCC_VERSION) || \ - defined(HEDLEY_INTEL_VERSION) || \ - defined(HEDLEY_TINYC_VERSION) || \ - defined(HEDLEY_TI_VERSION) || \ - defined(__clang__) -# define HEDLEY__IS_CONSTEXPR(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ - ((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) -# endif +#if HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || \ + HEDLEY_TINYC_VERSION_CHECK(0, 9, 24) +#if defined(__INTPTR_TYPE__) +#define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*)((__INTPTR_TYPE__)((expr)*0)) : (int*)0)), int*) +#else +#include +#define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*)((intptr_t)((expr)*0)) : (int*)0)), int*) +#endif +#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && !defined(HEDLEY_PGI_VERSION)) || \ + HEDLEY_HAS_EXTENSION(c_generic_selections) || HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) || \ + HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || HEDLEY_ARM_VERSION_CHECK(5, 3, 0) +#if defined(__INTPTR_TYPE__) +#define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*)((__INTPTR_TYPE__)((expr)*0)) : (int*)0), int* : 1, void* : 0) +#else +#include +#define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*)((intptr_t)*0) : (int*)0), int* : 1, void* : 0) +#endif +#elif defined(HEDLEY_GCC_VERSION) || defined(HEDLEY_INTEL_VERSION) || defined(HEDLEY_TINYC_VERSION) || defined(HEDLEY_TI_VERSION) || \ + defined(__clang__) +#define HEDLEY__IS_CONSTEXPR(expr) (sizeof(void) != sizeof(*(1 ? ((void*)((expr)*0L)) : ((struct { char v[sizeof(void) * 2]; }*)1)))) +#endif #endif #if defined(HEDLEY__IS_CONSTEXPR) -# if !defined(HEDLEY_IS_CONSTANT) -# define HEDLEY_IS_CONSTANT(expr) HEDLEY__IS_CONSTEXPR(expr) -# endif -# define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) +#if !defined(HEDLEY_IS_CONSTANT) +#define HEDLEY_IS_CONSTANT(expr) HEDLEY__IS_CONSTEXPR(expr) +#endif +#define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) #else -# if !defined(HEDLEY_IS_CONSTANT) -# define HEDLEY_IS_CONSTANT(expr) (0) -# endif -# define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#if !defined(HEDLEY_IS_CONSTANT) +#define HEDLEY_IS_CONSTANT(expr) (0) +#endif +#define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(HEDLEY_BEGIN_C_DECLS) -# undef HEDLEY_BEGIN_C_DECLS +#undef HEDLEY_BEGIN_C_DECLS #endif #if defined(HEDLEY_END_C_DECLS) -# undef HEDLEY_END_C_DECLS +#undef HEDLEY_END_C_DECLS #endif #if defined(HEDLEY_C_DECL) -# undef HEDLEY_C_DECL +#undef HEDLEY_C_DECL #endif #if defined(__cplusplus) -# define HEDLEY_BEGIN_C_DECLS extern "C" { -# define HEDLEY_END_C_DECLS } -# define HEDLEY_C_DECL extern "C" +#define HEDLEY_BEGIN_C_DECLS extern "C" { +#define HEDLEY_END_C_DECLS } +#define HEDLEY_C_DECL extern "C" #else -# define HEDLEY_BEGIN_C_DECLS -# define HEDLEY_END_C_DECLS -# define HEDLEY_C_DECL +#define HEDLEY_BEGIN_C_DECLS +#define HEDLEY_END_C_DECLS +#define HEDLEY_C_DECL #endif #if defined(HEDLEY_STATIC_ASSERT) -# undef HEDLEY_STATIC_ASSERT -#endif -#if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - HEDLEY_HAS_FEATURE(c_static_assert) || \ - HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) -# define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ - (defined(__cplusplus) && (__cplusplus >= 201703L)) || \ - HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - (defined(__cplusplus) && HEDLEY_TI_VERSION_CHECK(8,3,0)) -# define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) +#undef HEDLEY_STATIC_ASSERT +#endif +#if !defined(__cplusplus) && \ + ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || HEDLEY_HAS_FEATURE(c_static_assert) || \ + HEDLEY_GCC_VERSION_CHECK(6, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || defined(_Static_assert)) +#define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif (defined(__cplusplus) && (__cplusplus >= 201703L)) || HEDLEY_MSVC_VERSION_CHECK(16, 0, 0) || \ + (defined(__cplusplus) && HEDLEY_TI_VERSION_CHECK(8, 3, 0)) +#define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) #elif defined(__cplusplus) && (__cplusplus >= 201103L) -# define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) +#define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) #else -# define HEDLEY_STATIC_ASSERT(expr, message) +#define HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(HEDLEY_CONST_CAST) -# undef HEDLEY_CONST_CAST +#undef HEDLEY_CONST_CAST #endif #if defined(__cplusplus) -# define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - HEDLEY_HAS_WARNING("-Wcast-qual") || \ - HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - HEDLEY_DIAGNOSTIC_POP \ +#define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif HEDLEY_HAS_WARNING("-Wcast-qual") || HEDLEY_GCC_VERSION_CHECK(4, 6, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_CONST_CAST(T, expr) \ + (__extension__({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL((T)(expr)); \ + HEDLEY_DIAGNOSTIC_POP \ })) #else -# define HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#define HEDLEY_CONST_CAST(T, expr) ((T)(expr)) #endif #if defined(HEDLEY_REINTERPRET_CAST) -# undef HEDLEY_REINTERPRET_CAST +#undef HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) -# define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else -# define HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) +#define HEDLEY_REINTERPRET_CAST(T, expr) (*((T*)&(expr))) #endif #if defined(HEDLEY_STATIC_CAST) -# undef HEDLEY_STATIC_CAST +#undef HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) -# define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else -# define HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#define HEDLEY_STATIC_CAST(T, expr) ((T)(expr)) #endif #if defined(HEDLEY_CPP_CAST) -# undef HEDLEY_CPP_CAST +#undef HEDLEY_CPP_CAST #endif #if defined(__cplusplus) -# define HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#define HEDLEY_CPP_CAST(T, expr) static_cast(expr) #else -# define HEDLEY_CPP_CAST(T, expr) (expr) +#define HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(HEDLEY_MESSAGE) -# undef HEDLEY_MESSAGE +#undef HEDLEY_MESSAGE #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_MESSAGE(msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - HEDLEY_PRAGMA(message msg) \ - HEDLEY_DIAGNOSTIC_POP -#elif \ - HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ - HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) -#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) -#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) -#elif HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +#define HEDLEY_MESSAGE(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(message msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) +#elif HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) +#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +#elif HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) +#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) #else -# define HEDLEY_MESSAGE(msg) +#define HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_WARNING) -# undef HEDLEY_WARNING +#undef HEDLEY_WARNING #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define HEDLEY_WARNING(msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - HEDLEY_PRAGMA(clang warning msg) \ - HEDLEY_DIAGNOSTIC_POP -#elif \ - HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - HEDLEY_PGI_VERSION_CHECK(18,4,0) -# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) -#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) +#define HEDLEY_WARNING(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(clang warning msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif HEDLEY_GCC_VERSION_CHECK(4, 8, 0) || HEDLEY_PGI_VERSION_CHECK(18, 4, 0) +#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) +#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) #else -# define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) +#define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_REQUIRE_MSG) -# undef HEDLEY_REQUIRE_MSG +#undef HEDLEY_REQUIRE_MSG #endif #if HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if HEDLEY_HAS_WARNING("-Wgcc-compat") -# define HEDLEY_REQUIRE_MSG(expr, msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((__diagnose_if__(!(expr), msg, "error"))) \ - HEDLEY_DIAGNOSTIC_POP -# else -# define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) -# endif +#if HEDLEY_HAS_WARNING("-Wgcc-compat") +#define HEDLEY_REQUIRE_MSG(expr, msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") __attribute__((__diagnose_if__(!(expr), msg, "error"))) HEDLEY_DIAGNOSTIC_POP +#else +#define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) +#endif #else -# define HEDLEY_REQUIRE_MSG(expr, msg) +#define HEDLEY_REQUIRE_MSG(expr, msg) #endif #if defined(HEDLEY_REQUIRE) -# undef HEDLEY_REQUIRE +#undef HEDLEY_REQUIRE #endif #define HEDLEY_REQUIRE(expr) HEDLEY_REQUIRE_MSG(expr, #expr) #if defined(HEDLEY_FLAGS) -# undef HEDLEY_FLAGS +#undef HEDLEY_FLAGS #endif #if HEDLEY_HAS_ATTRIBUTE(flag_enum) -# define HEDLEY_FLAGS __attribute__((__flag_enum__)) +#define HEDLEY_FLAGS __attribute__((__flag_enum__)) #endif #if defined(HEDLEY_FLAGS_CAST) -# undef HEDLEY_FLAGS_CAST -#endif -#if HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ - HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - HEDLEY_DIAGNOSTIC_POP \ +#undef HEDLEY_FLAGS_CAST +#endif +#if HEDLEY_INTEL_VERSION_CHECK(19, 0, 0) +#define HEDLEY_FLAGS_CAST(T, expr) \ + (__extension__({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)")((T)(expr)); \ + HEDLEY_DIAGNOSTIC_POP \ })) #else -# define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) +#define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) #endif /* Remaining macros are deprecated. */ #if defined(HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) -# undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) -# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) (0) #else -# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(HEDLEY_CLANG_HAS_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_BUILTIN) -# undef HEDLEY_CLANG_HAS_BUILTIN +#undef HEDLEY_CLANG_HAS_BUILTIN #endif #define HEDLEY_CLANG_HAS_BUILTIN(builtin) HEDLEY_HAS_BUILTIN(builtin) #if defined(HEDLEY_CLANG_HAS_FEATURE) -# undef HEDLEY_CLANG_HAS_FEATURE +#undef HEDLEY_CLANG_HAS_FEATURE #endif #define HEDLEY_CLANG_HAS_FEATURE(feature) HEDLEY_HAS_FEATURE(feature) #if defined(HEDLEY_CLANG_HAS_EXTENSION) -# undef HEDLEY_CLANG_HAS_EXTENSION +#undef HEDLEY_CLANG_HAS_EXTENSION #endif #define HEDLEY_CLANG_HAS_EXTENSION(extension) HEDLEY_HAS_EXTENSION(extension) #if defined(HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) -# undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_WARNING) -# undef HEDLEY_CLANG_HAS_WARNING +#undef HEDLEY_CLANG_HAS_WARNING #endif #define HEDLEY_CLANG_HAS_WARNING(warning) HEDLEY_HAS_WARNING(warning) #endif /* !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < X) */ - -namespace csv { +namespace csv +{ #ifdef _MSC_VER #pragma region Compatibility Macros #endif @@ -4699,59 +4695,59 @@ namespace csv { #define CSV_HAS_CXX17 #endif -#if CMAKE_CXX_STANDARD >= 14 || __cplusplus >= 201402L +#if CMAKE_CXX_STANDARD >= 14 || __cplusplus >= 201402L #define CSV_HAS_CXX14 #endif #ifdef CSV_HAS_CXX17 #include - /** @typedef string_view - * The string_view class used by this library. - */ + /** @typedef string_view + * The string_view class used by this library. + */ using string_view = std::string_view; #else - /** @typedef string_view - * The string_view class used by this library. - */ + /** @typedef string_view + * The string_view class used by this library. + */ using string_view = nonstd::string_view; #endif #ifdef CSV_HAS_CXX17 - #define IF_CONSTEXPR if constexpr - #define CONSTEXPR_VALUE constexpr +#define IF_CONSTEXPR if constexpr +#define CONSTEXPR_VALUE constexpr - #define CONSTEXPR_17 constexpr +#define CONSTEXPR_17 constexpr #else - #define IF_CONSTEXPR if - #define CONSTEXPR_VALUE const +#define IF_CONSTEXPR if +#define CONSTEXPR_VALUE const - #define CONSTEXPR_17 inline +#define CONSTEXPR_17 inline #endif #ifdef CSV_HAS_CXX14 template using enable_if_t = std::enable_if_t; - #define CONSTEXPR_14 constexpr - #define CONSTEXPR_VALUE_14 constexpr +#define CONSTEXPR_14 constexpr +#define CONSTEXPR_VALUE_14 constexpr #else template using enable_if_t = typename std::enable_if::type; - #define CONSTEXPR_14 inline - #define CONSTEXPR_VALUE_14 const +#define CONSTEXPR_14 inline +#define CONSTEXPR_VALUE_14 const #endif // Resolves g++ bug with regard to constexpr methods // See: https://stackoverflow.com/questions/36489369/constexpr-non-static-member-function-with-non-constexpr-constructor-gcc-clang-d #if defined __GNUC__ && !defined __clang__ - #if (__GNUC__ >= 7 &&__GNUC_MINOR__ >= 2) || (__GNUC__ >= 8) - #define CONSTEXPR constexpr - #endif - #else - #ifdef CSV_HAS_CXX17 - #define CONSTEXPR constexpr - #endif +#if (__GNUC__ >= 7 && __GNUC_MINOR__ >= 2) || (__GNUC__ >= 8) +#define CONSTEXPR constexpr +#endif +#else +#ifdef CSV_HAS_CXX17 +#define CONSTEXPR constexpr +#endif #endif #ifndef CONSTEXPR @@ -4762,7 +4758,8 @@ namespace csv { #pragma endregion #endif - namespace internals { + namespace internals + { // PAGE_SIZE macro could be already defined by the host system. #if defined(PAGE_SIZE) #undef PAGE_SIZE @@ -4770,14 +4767,15 @@ namespace csv { // Get operating system specific details #if defined(_WIN32) - inline int getpagesize() { + inline int getpagesize() + { _SYSTEM_INFO sys_info = {}; GetSystemInfo(&sys_info); return std::max(sys_info.dwPageSize, sys_info.dwAllocationGranularity); } const int PAGE_SIZE = getpagesize(); -#elif defined(__linux__) +#elif defined(__linux__) const int PAGE_SIZE = getpagesize(); #else /** Size of a memory page in bytes. Used by @@ -4792,7 +4790,8 @@ namespace csv { constexpr size_t ITERATION_CHUNK_SIZE = 10000000; // 10MB template - inline bool is_equal(T a, T b, T epsilon = 0.001) { + inline bool is_equal(T a, T b, T epsilon = 0.001) + { /** Returns true if two floating point values are about the same */ static_assert(std::is_floating_point::value, "T must be a floating point type."); return std::abs(a - b) < epsilon; @@ -4804,17 +4803,19 @@ namespace csv { * * @see quote_escape_flag */ - enum class ParseFlags { + enum class ParseFlags + { QUOTE_ESCAPE_QUOTE = 0, /**< A quote inside or terminating a quote_escaped field */ - QUOTE = 2 | 1, /**< Characters which may signify a quote escape */ - NOT_SPECIAL = 4, /**< Characters with no special meaning or escaped delimiters and newlines */ - DELIMITER = 4 | 2, /**< Characters which signify a new field */ - NEWLINE = 4 | 2 | 1 /**< Characters which signify a new row */ + QUOTE = 2 | 1, /**< Characters which may signify a quote escape */ + NOT_SPECIAL = 4, /**< Characters with no special meaning or escaped delimiters and newlines */ + DELIMITER = 4 | 2, /**< Characters which signify a new field */ + NEWLINE = 4 | 2 | 1 /**< Characters which signify a new row */ }; /** Transform the ParseFlags given the context of whether or not the current * field is quote escaped */ - constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept { + constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept + { return (ParseFlags)((int)flag & ~((int)ParseFlags::QUOTE * quote_escape)); } @@ -4842,29 +4843,32 @@ namespace csv { /** An array which maps ASCII chars to a flag indicating if it is whitespace */ using WhitespaceMap = std::array; - } + } // namespace internals /** Integer indicating a requested column wasn't found. */ constexpr int CSV_NOT_FOUND = -1; -} - +} // namespace csv -namespace csv { - namespace internals { +namespace csv +{ + namespace internals + { struct ColNames; using ColNamesPtr = std::shared_ptr; /** @struct ColNames - * A data structure for handling column name information. - * - * These are created by CSVReader and passed (via smart pointer) - * to CSVRow objects it creates, thus - * allowing for indexing by column name. - */ - struct ColNames { + * A data structure for handling column name information. + * + * These are created by CSVReader and passed (via smart pointer) + * to CSVRow objects it creates, thus + * allowing for indexing by column name. + */ + struct ColNames + { public: ColNames() = default; - ColNames(const std::vector& names) { + ColNames(const std::vector& names) + { set_col_names(names); } @@ -4872,15 +4876,18 @@ namespace csv { void set_col_names(const std::vector&); int index_of(csv::string_view) const; - bool empty() const noexcept { return this->col_names.empty(); } + bool empty() const noexcept + { + return this->col_names.empty(); + } size_t size() const noexcept; private: std::vector col_names; std::unordered_map col_pos; }; - } -} + } // namespace internals +} // namespace csv /** @file * Defines an object used to store CSV format settings */ @@ -4890,31 +4897,35 @@ namespace csv { #include #include - -namespace csv { - namespace internals { +namespace csv +{ + namespace internals + { class IBasicCSVParser; } class CSVReader; /** Determines how to handle rows that are shorter or longer than the majority */ - enum class VariableColumnPolicy { + enum class VariableColumnPolicy + { THROW = -1, IGNORE_ROW = 0, - KEEP = 1 + KEEP = 1 }; /** Stores the inferred format of a CSV file. */ - struct CSVGuessResult { + struct CSVGuessResult + { char delim; int header_row; }; /** Stores information about how to parse a CSV file. - * Can be used to construct a csv::CSVReader. + * Can be used to construct a csv::CSVReader. */ - class CSVFormat { + class CSVFormat + { public: /** Settings for parsing a RFC 4180 CSV file */ CSVFormat() = default; @@ -4926,18 +4937,18 @@ namespace csv { CSVFormat& delimiter(char delim); /** Sets a list of potential delimiters - * + * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] delim An array of possible delimiters to try parsing the CSV with */ - CSVFormat& delimiter(const std::vector & delim); + CSVFormat& delimiter(const std::vector& delim); /** Sets the whitespace characters to be trimmed * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] ws An array of whitespace characters that should be trimmed */ - CSVFormat& trim(const std::vector & ws); + CSVFormat& trim(const std::vector& ws); /** Sets the quote character * @@ -4962,64 +4973,88 @@ namespace csv { * @note Equivalent to `header_row(-1)` * */ - CSVFormat& no_header() { + CSVFormat& no_header() + { this->header_row(-1); return *this; } /** Turn quoting on or off */ - CSVFormat& quote(bool use_quote) { + CSVFormat& quote(bool use_quote) + { this->no_quote = !use_quote; return *this; } /** Tells the parser how to handle columns of a different length than the others */ - CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) { + CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) + { this->variable_column_policy = policy; return *this; } /** Tells the parser how to handle columns of a different length than the others */ - CONSTEXPR_14 CSVFormat& variable_columns(bool policy) { + CONSTEXPR_14 CSVFormat& variable_columns(bool policy) + { this->variable_column_policy = (VariableColumnPolicy)policy; return *this; } - #ifndef DOXYGEN_SHOULD_SKIP_THIS - char get_delim() const { +#ifndef DOXYGEN_SHOULD_SKIP_THIS + char get_delim() const + { // This error should never be received by end users. - if (this->possible_delimiters.size() > 1) { + if (this->possible_delimiters.size() > 1) + { throw std::runtime_error("There is more than one possible delimiter."); } return this->possible_delimiters.at(0); } - CONSTEXPR bool is_quoting_enabled() const { return !this->no_quote; } - CONSTEXPR char get_quote_char() const { return this->quote_char; } - CONSTEXPR int get_header() const { return this->header; } - std::vector get_possible_delims() const { return this->possible_delimiters; } - std::vector get_trim_chars() const { return this->trim_chars; } - CONSTEXPR VariableColumnPolicy get_variable_column_policy() const { return this->variable_column_policy; } - #endif - + CONSTEXPR bool is_quoting_enabled() const + { + return !this->no_quote; + } + CONSTEXPR char get_quote_char() const + { + return this->quote_char; + } + CONSTEXPR int get_header() const + { + return this->header; + } + std::vector get_possible_delims() const + { + return this->possible_delimiters; + } + std::vector get_trim_chars() const + { + return this->trim_chars; + } + CONSTEXPR VariableColumnPolicy get_variable_column_policy() const + { + return this->variable_column_policy; + } +#endif + /** CSVFormat for guessing the delimiter */ - CSV_INLINE static CSVFormat guess_csv() { + CSV_INLINE static CSVFormat guess_csv() + { CSVFormat format; - format.delimiter({ ',', '|', '\t', ';', '^' }) - .quote('"') - .header_row(0); + format.delimiter({ ',', '|', '\t', ';', '^' }).quote('"').header_row(0); return format; } - bool guess_delim() { + bool guess_delim() + { return this->possible_delimiters.size() > 1; } friend CSVReader; friend internals::IBasicCSVParser; - + private: /**< Throws an error if delimiters and trim characters overlap */ void assert_no_char_overlap(); @@ -5045,65 +5080,67 @@ namespace csv { /**< Allow variable length columns? */ VariableColumnPolicy variable_column_policy = VariableColumnPolicy::IGNORE_ROW; }; -} +} // namespace csv /** @file * Defines the data type used for storing information about a CSV row */ #include #include -#include // For CSVField #include // For CSVField +#include // For CSVField +#include +#include #include #include -#include -#include #include /** @file * @brief Implements data type parsing functionality */ -#include +#include #include +#include #include -#include - -namespace csv { +namespace csv +{ /** Enumerates the different CSV field types that are * recognized by this library * * @note Overflowing integers will be stored and classified as doubles. * @note Unlike previous releases, integer enums here are platform agnostic. */ - enum class DataType { + enum class DataType + { UNKNOWN = -1, - CSV_NULL, /**< Empty string */ + CSV_NULL, /**< Empty string */ CSV_STRING, /**< Non-numeric string */ - CSV_INT8, /**< 8-bit integer */ - CSV_INT16, /**< 16-bit integer (short on MSVC/GCC) */ - CSV_INT32, /**< 32-bit integer (int on MSVC/GCC) */ - CSV_INT64, /**< 64-bit integer (long long on MSVC/GCC) */ - CSV_DOUBLE /**< Floating point value */ + CSV_INT8, /**< 8-bit integer */ + CSV_INT16, /**< 16-bit integer (short on MSVC/GCC) */ + CSV_INT32, /**< 32-bit integer (int on MSVC/GCC) */ + CSV_INT64, /**< 64-bit integer (long long on MSVC/GCC) */ + CSV_DOUBLE /**< Floating point value */ }; static_assert(DataType::CSV_STRING < DataType::CSV_INT8, "String type should come before numeric types."); static_assert(DataType::CSV_INT8 < DataType::CSV_INT64, "Smaller integer types should come before larger integer types."); static_assert(DataType::CSV_INT64 < DataType::CSV_DOUBLE, "Integer types should come before floating point value types."); - namespace internals { + namespace internals + { /** Compute 10 to the power of n */ template - HEDLEY_CONST CONSTEXPR_14 - long double pow10(const T& n) noexcept { - long double multiplicand = n > 0 ? 10 : 0.1, - ret = 1; + HEDLEY_CONST CONSTEXPR_14 long double pow10(const T& n) noexcept + { + long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; // Make all numbers positive T iterations = n > 0 ? n : -n; - - for (T i = 0; i < iterations; i++) { + + for (T i = 0; i < iterations; i++) + { ret *= multiplicand; } @@ -5112,12 +5149,12 @@ namespace csv { /** Compute 10 to the power of n */ template<> - HEDLEY_CONST CONSTEXPR_14 - long double pow10(const unsigned& n) noexcept { - long double multiplicand = n > 0 ? 10 : 0.1, - ret = 1; + HEDLEY_CONST CONSTEXPR_14 long double pow10(const unsigned& n) noexcept + { + long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; - for (unsigned i = 0; i < n; i++) { + for (unsigned i = 0; i < n; i++) + { ret *= multiplicand; } @@ -5127,28 +5164,47 @@ namespace csv { #ifndef DOXYGEN_SHOULD_SKIP_THIS /** Private site-indexed array mapping byte sizes to an integer size enum */ constexpr DataType int_type_arr[8] = { - DataType::CSV_INT8, // 1 + DataType::CSV_INT8, // 1 DataType::CSV_INT16, // 2 DataType::UNKNOWN, DataType::CSV_INT32, // 4 - DataType::UNKNOWN, - DataType::UNKNOWN, - DataType::UNKNOWN, - DataType::CSV_INT64 // 8 + DataType::UNKNOWN, DataType::UNKNOWN, DataType::UNKNOWN, + DataType::CSV_INT64 // 8 }; template - inline DataType type_num() { + inline DataType type_num() + { static_assert(std::is_integral::value, "T should be an integral type."); static_assert(sizeof(T) <= 8, "Byte size must be no greater than 8."); return int_type_arr[sizeof(T) - 1]; } - template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } - template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } - template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } - template<> inline DataType type_num() { return DataType::CSV_NULL; } - template<> inline DataType type_num() { return DataType::CSV_STRING; } + template<> + inline DataType type_num() + { + return DataType::CSV_DOUBLE; + } + template<> + inline DataType type_num() + { + return DataType::CSV_DOUBLE; + } + template<> + inline DataType type_num() + { + return DataType::CSV_DOUBLE; + } + template<> + inline DataType type_num() + { + return DataType::CSV_NULL; + } + template<> + inline DataType type_num() + { + return DataType::CSV_STRING; + } CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr); #endif @@ -5160,27 +5216,32 @@ namespace csv { * byte sizes */ template - CONSTEXPR_14 long double get_int_max() { - static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, - "Bytes must be a power of 2 below 8."); + CONSTEXPR_14 long double get_int_max() + { + static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); - IF_CONSTEXPR (sizeof(signed char) == Bytes) { + IF_CONSTEXPR(sizeof(signed char) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR (sizeof(short) == Bytes) { + IF_CONSTEXPR(sizeof(short) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR (sizeof(int) == Bytes) { + IF_CONSTEXPR(sizeof(int) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR (sizeof(long int) == Bytes) { + IF_CONSTEXPR(sizeof(long int) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR (sizeof(long long int) == Bytes) { + IF_CONSTEXPR(sizeof(long long int) == Bytes) + { return (long double)std::numeric_limits::max(); } @@ -5191,27 +5252,32 @@ namespace csv { * an unsigned integer of that size */ template - CONSTEXPR_14 long double get_uint_max() { - static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, - "Bytes must be a power of 2 below 8."); + CONSTEXPR_14 long double get_uint_max() + { + static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); - IF_CONSTEXPR(sizeof(unsigned char) == Bytes) { + IF_CONSTEXPR(sizeof(unsigned char) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned short) == Bytes) { + IF_CONSTEXPR(sizeof(unsigned short) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned int) == Bytes) { + IF_CONSTEXPR(sizeof(unsigned int) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) { + IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) + { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned long long int) == Bytes) { + IF_CONSTEXPR(sizeof(unsigned long long int) == Bytes) + { return (long double)std::numeric_limits::max(); } @@ -5246,17 +5312,17 @@ namespace csv { * the exponential part of a number written (possibly) in scientific notation * parse the exponent */ - HEDLEY_PRIVATE CONSTEXPR_14 - DataType _process_potential_exponential( - csv::string_view exponential_part, - const long double& coeff, - long double * const out) { + HEDLEY_PRIVATE CONSTEXPR_14 DataType + _process_potential_exponential(csv::string_view exponential_part, const long double& coeff, long double* const out) + { long double exponent = 0; auto result = data_type(exponential_part, &exponent); // Exponents in scientific notation should not be decimal numbers - if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) { - if (out) *out = coeff * pow10(exponent); + if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) + { + if (out) + *out = coeff * pow10(exponent); return DataType::CSV_DOUBLE; } @@ -5266,8 +5332,8 @@ namespace csv { /** Given the absolute value of an integer, determine what numeric type * it fits in */ - HEDLEY_PRIVATE HEDLEY_PURE CONSTEXPR_14 - DataType _determine_integral_type(const long double& number) noexcept { + HEDLEY_PRIVATE HEDLEY_PURE CONSTEXPR_14 DataType _determine_integral_type(const long double& number) noexcept + { // We can assume number is always non-negative assert(number >= 0); @@ -5295,40 +5361,41 @@ namespace csv { * get stored */ CONSTEXPR_14 - DataType data_type(csv::string_view in, long double* const out) { + DataType data_type(csv::string_view in, long double* const out) + { // Empty string --> NULL if (in.size() == 0) return DataType::CSV_NULL; - bool ws_allowed = true, - neg_allowed = true, - dot_allowed = true, - digit_allowed = true, - has_digit = false, - prob_float = false; + bool ws_allowed = true, neg_allowed = true, dot_allowed = true, digit_allowed = true, has_digit = false, prob_float = false; unsigned places_after_decimal = 0; - long double integral_part = 0, - decimal_part = 0; + long double integral_part = 0, decimal_part = 0; - for (size_t i = 0, ilen = in.size(); i < ilen; i++) { + for (size_t i = 0, ilen = in.size(); i < ilen; i++) + { const char& current = in[i]; - switch (current) { + switch (current) + { case ' ': - if (!ws_allowed) { - if (isdigit(in[i - 1])) { + if (!ws_allowed) + { + if (isdigit(in[i - 1])) + { digit_allowed = false; ws_allowed = true; } - else { + else + { // Ex: '510 123 4567' return DataType::CSV_STRING; } } break; case '-': - if (!neg_allowed) { + if (!neg_allowed) + { // Ex: '510-123-4567' return DataType::CSV_STRING; } @@ -5336,7 +5403,8 @@ namespace csv { neg_allowed = false; break; case '.': - if (!dot_allowed) { + if (!dot_allowed) + { return DataType::CSV_STRING; } @@ -5346,27 +5414,29 @@ namespace csv { case 'e': case 'E': // Process scientific notation - if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) { + if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) + { size_t exponent_start_idx = i + 1; prob_float = true; // Strip out plus sign - if (in[i + 1] == '+') { + if (in[i + 1] == '+') + { exponent_start_idx++; } return _process_potential_exponential( in.substr(exponent_start_idx), neg_allowed ? integral_part + decimal_part : -(integral_part + decimal_part), - out - ); + out); } return DataType::CSV_STRING; break; default: short digit = static_cast(current - '0'); - if (digit >= 0 && digit <= 9) { + if (digit >= 0 && digit <= 9) + { // Process digit has_digit = true; @@ -5381,16 +5451,19 @@ namespace csv { else integral_part = (integral_part * 10) + digit; } - else { + else + { return DataType::CSV_STRING; } } } // No non-numeric/non-whitespace characters found - if (has_digit) { + if (has_digit) + { long double number = integral_part + decimal_part; - if (out) { + if (out) + { *out = neg_allowed ? number : -number; } @@ -5400,25 +5473,28 @@ namespace csv { // Just whitespace return DataType::CSV_NULL; } - } -} + } // namespace internals +} // namespace csv -namespace csv { - namespace internals { +namespace csv +{ + namespace internals + { class IBasicCSVParser; static const std::string ERROR_NAN = "Not a number."; static const std::string ERROR_OVERFLOW = "Overflow error."; - static const std::string ERROR_FLOAT_TO_INT = - "Attempted to convert a floating point value to an integral type."; + static const std::string ERROR_FLOAT_TO_INT = "Attempted to convert a floating point value to an integral type."; static const std::string ERROR_NEG_TO_UNSIGNED = "Negative numbers cannot be converted to unsigned types."; - + std::string json_escape_string(csv::string_view s) noexcept; /** A barebones class used for describing CSV fields */ - struct RawCSVField { + struct RawCSVField + { RawCSVField() = default; - RawCSVField(size_t _start, size_t _length, bool _double_quote = false) { + RawCSVField(size_t _start, size_t _length, bool _double_quote = false) + { start = _start; length = _length; has_double_quote = _double_quote; @@ -5428,7 +5504,7 @@ namespace csv { size_t start; /** The length of the row, ignoring quote escape characters */ - size_t length; + size_t length; /** Whether or not the field contains an escaped quote */ bool has_double_quote; @@ -5445,11 +5521,13 @@ namespace csv { * as long as the writing thread does not actively touch fields which are being * read. */ - class CSVFieldList { + class CSVFieldList + { public: /** Construct a CSVFieldList which allocates blocks of a certain size */ - CSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) : - _single_buffer_capacity(single_buffer_capacity) { + CSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) + : _single_buffer_capacity(single_buffer_capacity) + { this->allocate(); } @@ -5457,21 +5535,25 @@ namespace csv { CSVFieldList(const CSVFieldList& other) = delete; // CSVFieldArrays may be moved - CSVFieldList(CSVFieldList&& other) : - _single_buffer_capacity(other._single_buffer_capacity) { + CSVFieldList(CSVFieldList&& other) + : _single_buffer_capacity(other._single_buffer_capacity) + { buffers = std::move(other.buffers); _current_buffer_size = other._current_buffer_size; _back = other._back; } - ~CSVFieldList() { + ~CSVFieldList() + { for (auto& buffer : buffers) delete[] buffer; } - template - void emplace_back(Args&&... args) { - if (this->_current_buffer_size == this->_single_buffer_capacity) { + template + void emplace_back(Args&&... args) + { + if (this->_current_buffer_size == this->_single_buffer_capacity) + { this->allocate(); } @@ -5479,7 +5561,8 @@ namespace csv { _current_buffer_size++; } - size_t size() const noexcept { + size_t size() const noexcept + { return this->_current_buffer_size + ((this->buffers.size() - 1) * this->_single_buffer_capacity); } @@ -5500,9 +5583,9 @@ namespace csv { void allocate(); }; - /** A class for storing raw CSV data and associated metadata */ - struct RawCSVData { + struct RawCSVData + { std::shared_ptr _data = nullptr; csv::string_view data = ""; @@ -5519,80 +5602,95 @@ namespace csv { }; using RawCSVDataPtr = std::shared_ptr; - } + } // namespace internals /** - * @class CSVField - * @brief Data type representing individual CSV values. - * CSVFields can be obtained by using CSVRow::operator[] - */ - class CSVField { + * @class CSVField + * @brief Data type representing individual CSV values. + * CSVFields can be obtained by using CSVRow::operator[] + */ + class CSVField + { public: /** Constructs a CSVField from a string_view */ - constexpr explicit CSVField(csv::string_view _sv) noexcept : sv(_sv) { }; + constexpr explicit CSVField(csv::string_view _sv) noexcept + : sv(_sv){}; - operator std::string() const { + operator std::string() const + { return std::string(" ") + std::string(this->sv); } /** Returns the value casted to the requested type, performing type checking before. - * - * \par Valid options for T - * - std::string or csv::string_view - * - signed integral types (signed char, short, int, long int, long long int) - * - floating point types (float, double, long double) - * - unsigned integers are not supported at this time, but may be in a later release - * - * \par Invalid conversions - * - Converting non-numeric values to any numeric type - * - Converting floating point values to integers - * - Converting a large integer to a smaller type that will not hold it - * - * @note This method is capable of parsing scientific E-notation. - * See [this page](md_docs_source_scientific_notation.html) - * for more details. - * - * @throws std::runtime_error Thrown if an invalid conversion is performed. - * - * @warning Currently, conversions to floating point types are not - * checked for loss of precision - * - * @warning Any string_views returned are only guaranteed to be valid - * if the parent CSVRow is still alive. If you are concerned - * about object lifetimes, then grab a std::string or a - * numeric value. - * - */ - template T get() { - IF_CONSTEXPR(std::is_arithmetic::value) { + * + * \par Valid options for T + * - std::string or csv::string_view + * - signed integral types (signed char, short, int, long int, long long int) + * - floating point types (float, double, long double) + * - unsigned integers are not supported at this time, but may be in a later release + * + * \par Invalid conversions + * - Converting non-numeric values to any numeric type + * - Converting floating point values to integers + * - Converting a large integer to a smaller type that will not hold it + * + * @note This method is capable of parsing scientific E-notation. + * See [this page](md_docs_source_scientific_notation.html) + * for more details. + * + * @throws std::runtime_error Thrown if an invalid conversion is performed. + * + * @warning Currently, conversions to floating point types are not + * checked for loss of precision + * + * @warning Any string_views returned are only guaranteed to be valid + * if the parent CSVRow is still alive. If you are concerned + * about object lifetimes, then grab a std::string or a + * numeric value. + * + */ + template + T get() + { + IF_CONSTEXPR(std::is_arithmetic::value) + { // Note: this->type() also converts the CSV value to float - if (this->type() <= DataType::CSV_STRING) { + if (this->type() <= DataType::CSV_STRING) + { throw std::runtime_error(internals::ERROR_NAN); } } - IF_CONSTEXPR(std::is_integral::value) { + IF_CONSTEXPR(std::is_integral::value) + { // Note: this->is_float() also converts the CSV value to float - if (this->is_float()) { + if (this->is_float()) + { throw std::runtime_error(internals::ERROR_FLOAT_TO_INT); } - IF_CONSTEXPR(std::is_unsigned::value) { - if (this->value < 0) { + IF_CONSTEXPR(std::is_unsigned::value) + { + if (this->value < 0) + { throw std::runtime_error(internals::ERROR_NEG_TO_UNSIGNED); } } } // Allow fallthrough from previous if branch - IF_CONSTEXPR(!std::is_floating_point::value) { - IF_CONSTEXPR(std::is_unsigned::value) { + IF_CONSTEXPR(!std::is_floating_point::value) + { + IF_CONSTEXPR(std::is_unsigned::value) + { // Quick hack to perform correct unsigned integer boundary checks - if (this->value > internals::get_uint_max()) { + if (this->value > internals::get_uint_max()) + { throw std::runtime_error(internals::ERROR_OVERFLOW); } } - else if (internals::type_num() < this->_type) { + else if (internals::type_num() < this->_type) + { throw std::runtime_error(internals::ERROR_OVERFLOW); } } @@ -5619,11 +5717,12 @@ namespace csv { template CONSTEXPR_14 bool operator==(T other) const noexcept { - static_assert(std::is_arithmetic::value, - "T should be a numeric value."); + static_assert(std::is_arithmetic::value, "T should be a numeric value."); - if (this->_type != DataType::UNKNOWN) { - if (this->_type == DataType::CSV_STRING) { + if (this->_type != DataType::UNKNOWN) + { + if (this->_type == DataType::CSV_STRING) + { return false; } @@ -5631,7 +5730,8 @@ namespace csv { } long double out = 0; - if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) { + if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) + { return false; } @@ -5639,62 +5739,95 @@ namespace csv { } /** Return a string view over the field's contents */ - CONSTEXPR csv::string_view get_sv() const noexcept { return this->sv; } + CONSTEXPR csv::string_view get_sv() const noexcept + { + return this->sv; + } /** Returns true if field is an empty string or string of whitespace characters */ - CONSTEXPR_14 bool is_null() noexcept { return type() == DataType::CSV_NULL; } + CONSTEXPR_14 bool is_null() noexcept + { + return type() == DataType::CSV_NULL; + } /** Returns true if field is a non-numeric, non-empty string */ - CONSTEXPR_14 bool is_str() noexcept { return type() == DataType::CSV_STRING; } + CONSTEXPR_14 bool is_str() noexcept + { + return type() == DataType::CSV_STRING; + } /** Returns true if field is an integer or float */ - CONSTEXPR_14 bool is_num() noexcept { return type() >= DataType::CSV_INT8; } + CONSTEXPR_14 bool is_num() noexcept + { + return type() >= DataType::CSV_INT8; + } /** Returns true if field is an integer */ - CONSTEXPR_14 bool is_int() noexcept { + CONSTEXPR_14 bool is_int() noexcept + { return (type() >= DataType::CSV_INT8) && (type() <= DataType::CSV_INT64); } /** Returns true if field is a floating point value */ - CONSTEXPR_14 bool is_float() noexcept { return type() == DataType::CSV_DOUBLE; }; + CONSTEXPR_14 bool is_float() noexcept + { + return type() == DataType::CSV_DOUBLE; + }; /** Return the type of the underlying CSV data */ - CONSTEXPR_14 DataType type() noexcept { + CONSTEXPR_14 DataType type() noexcept + { this->get_value(); return _type; } private: - long double value = 0; /**< Cached numeric value */ + long double value = 0; /**< Cached numeric value */ csv::string_view sv = ""; /**< A pointer to this field's text */ DataType _type = DataType::UNKNOWN; /**< Cached data type value */ - CONSTEXPR_14 void get_value() noexcept { + CONSTEXPR_14 void get_value() noexcept + { /* Check to see if value has been cached previously, if not * evaluate it */ - if ((int)_type < 0) { + if ((int)_type < 0) + { this->_type = internals::data_type(this->sv, &this->value); } } }; /** Data structure for representing CSV rows */ - class CSVRow { + class CSVRow + { public: friend internals::IBasicCSVParser; CSVRow() = default; - + /** Construct a CSVRow from a RawCSVDataPtr */ - CSVRow(internals::RawCSVDataPtr _data) : data(_data) {} + CSVRow(internals::RawCSVDataPtr _data) + : data(_data) + { + } CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds) - : data(_data), data_start(_data_start), fields_start(_field_bounds) {} + : data(_data) + , data_start(_data_start) + , fields_start(_field_bounds) + { + } /** Indicates whether row is empty or not */ - CONSTEXPR bool empty() const noexcept { return this->size() == 0; } + CONSTEXPR bool empty() const noexcept + { + return this->size() == 0; + } /** Return the number of fields in this row */ - CONSTEXPR size_t size() const noexcept { return row_length; } + CONSTEXPR size_t size() const noexcept + { + return row_length; + } /** @name Value Retrieval */ ///@{ @@ -5704,7 +5837,8 @@ namespace csv { std::string to_json_array(const std::vector& subset = {}) const; /** Retrieve this row's associated column names */ - std::vector get_col_names() const { + std::vector get_col_names() const + { return this->data->col_names->get_col_names(); } @@ -5718,7 +5852,8 @@ namespace csv { /** A random access iterator over the contents of a CSV row. * Each iterator points to a CSVField. */ - class iterator { + class iterator + { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVField; @@ -5729,10 +5864,10 @@ namespace csv { #ifdef _MSC_BUILD using pointer = std::shared_ptr; #else - using pointer = CSVField * ; + using pointer = CSVField*; #endif - using reference = CSVField & ; + using reference = CSVField&; using iterator_category = std::random_access_iterator_tag; #endif iterator(const CSVRow*, int i); @@ -5748,20 +5883,24 @@ namespace csv { iterator operator-(difference_type n) const; /** Two iterators are equal if they point to the same field */ - CONSTEXPR bool operator==(const iterator& other) const noexcept { + CONSTEXPR bool operator==(const iterator& other) const noexcept + { return this->i == other.i; }; - CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } + CONSTEXPR bool operator!=(const iterator& other) const noexcept + { + return !operator==(other); + } #ifndef NDEBUG friend CSVRow; #endif private: - const CSVRow * daddy = nullptr; // Pointer to parent + const CSVRow* daddy = nullptr; // Pointer to parent std::shared_ptr field = nullptr; // Current field pointed at - int i = 0; // Index of current field + int i = 0; // Index of current field }; /** A reverse iterator over the contents of a CSVRow. */ @@ -5770,7 +5909,7 @@ namespace csv { /** @name Iterators * @brief Each iterator points to a CSVField object. */ - ///@{ + ///@{ iterator begin() const; iterator end() const noexcept; reverse_iterator rbegin() const noexcept; @@ -5798,7 +5937,8 @@ namespace csv { #endif /** Retrieve this field's original string */ template<> - inline std::string CSVField::get() { + inline std::string CSVField::get() + { return std::string(this->sv); } @@ -5808,13 +5948,15 @@ namespace csv { * CSVRow is still alive. */ template<> - CONSTEXPR_14 csv::string_view CSVField::get() { + CONSTEXPR_14 csv::string_view CSVField::get() + { return this->sv; } /** Retrieve this field's value as a long double */ template<> - CONSTEXPR_14 long double CSVField::get() { + CONSTEXPR_14 long double CSVField::get() + { if (!is_num()) throw std::runtime_error(internals::ERROR_NAN); @@ -5826,7 +5968,7 @@ namespace csv { /** Compares the contents of this field to a string */ template<> - CONSTEXPR bool CSVField::operator==(const char * other) const noexcept + CONSTEXPR bool CSVField::operator==(const char* other) const noexcept { return this->sv == other; } @@ -5837,23 +5979,27 @@ namespace csv { { return this->sv == other; } -} +} // namespace csv -inline std::ostream& operator << (std::ostream& os, csv::CSVField const& value) { +inline std::ostream& operator<<(std::ostream& os, csv::CSVField const& value) +{ os << std::string(value); return os; } - -namespace csv { - namespace internals { +namespace csv +{ + namespace internals + { /** Create a vector v where each index i corresponds to the * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ - HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) { + HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) + { std::array ret = {}; - for (int i = -128; i < 128; i++) { + for (int i = -128; i < 128; i++) + { const int arr_idx = i + 128; char ch = char(i); @@ -5872,7 +6018,8 @@ namespace csv { * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ - HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) { + HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) + { std::array ret = make_parse_flags(delimiter); ret[(size_t)quote_char + 128] = ParseFlags::QUOTE; return ret; @@ -5882,15 +6029,19 @@ namespace csv { * ASCII number for a character c and, v[i + 128] is true if * c is a whitespace character */ - HEDLEY_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) { + HEDLEY_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) + { std::array ret = {}; - for (int i = -128; i < 128; i++) { + for (int i = -128; i < 128; i++) + { const int arr_idx = i + 128; char ch = char(i); ret[arr_idx] = false; - for (size_t j = 0; j < n_chars; j++) { - if (ws_chars[j] == ch) { + for (size_t j = 0; j < n_chars; j++) + { + if (ws_chars[j] == ch) + { ret[arr_idx] = true; } } @@ -5899,7 +6050,8 @@ namespace csv { return ret; } - inline WhitespaceMap make_ws_flags(const std::vector& flags) { + inline WhitespaceMap make_ws_flags(const std::vector& flags) + { return make_ws_flags(flags.data(), flags.size()); } @@ -5915,81 +6067,112 @@ namespace csv { * to become populated */ template - class ThreadSafeDeque { + class ThreadSafeDeque + { public: - ThreadSafeDeque(size_t notify_size = 100) : _notify_size(notify_size) {}; - ThreadSafeDeque(const ThreadSafeDeque& other) { + ThreadSafeDeque(size_t notify_size = 100) + : _notify_size(notify_size){}; + ThreadSafeDeque(const ThreadSafeDeque& other) + { this->data = other.data; this->_notify_size = other._notify_size; } - ThreadSafeDeque(const std::deque& source) : ThreadSafeDeque() { + ThreadSafeDeque(const std::deque& source) + : ThreadSafeDeque() + { this->data = source; } - void clear() noexcept { this->data.clear(); } + void clear() noexcept + { + this->data.clear(); + } - bool empty() const noexcept { + bool empty() const noexcept + { return this->data.empty(); } - T& front() noexcept { + T& front() noexcept + { return this->data.front(); } - T& operator[](size_t n) { + T& operator[](size_t n) + { return this->data[n]; } - void push_back(T&& item) { + void push_back(T&& item) + { std::lock_guard lock{ this->_lock }; this->data.push_back(std::move(item)); - if (this->size() >= _notify_size) { + if (this->size() >= _notify_size) + { this->_cond.notify_all(); } } - T pop_front() noexcept { + T pop_front() noexcept + { std::lock_guard lock{ this->_lock }; T item = std::move(data.front()); data.pop_front(); return item; } - size_t size() const noexcept { return this->data.size(); } + size_t size() const noexcept + { + return this->data.size(); + } /** Returns true if a thread is actively pushing items to this deque */ - constexpr bool is_waitable() const noexcept { return this->_is_waitable; } + constexpr bool is_waitable() const noexcept + { + return this->_is_waitable; + } /** Wait for an item to become available */ - void wait() { - if (!is_waitable()) { + void wait() + { + if (!is_waitable()) + { return; } std::unique_lock lock{ this->_lock }; - this->_cond.wait(lock, [this] { return this->size() >= _notify_size || !this->is_waitable(); }); + this->_cond.wait( + lock, + [this] + { + return this->size() >= _notify_size || !this->is_waitable(); + }); lock.unlock(); } - typename std::deque::iterator begin() noexcept { + typename std::deque::iterator begin() noexcept + { return this->data.begin(); } - typename std::deque::iterator end() noexcept { + typename std::deque::iterator end() noexcept + { return this->data.end(); } /** Tell listeners that this deque is actively being pushed to */ - void notify_all() { + void notify_all() + { std::unique_lock lock{ this->_lock }; this->_is_waitable = true; this->_cond.notify_all(); } /** Tell all listeners to stop */ - void kill_all() { + void kill_all() + { std::unique_lock lock{ this->_lock }; this->_is_waitable = false; this->_cond.notify_all(); @@ -6004,29 +6187,37 @@ namespace csv { }; constexpr const int UNINITIALIZED_FIELD = -1; - } + } // namespace internals /** Standard type for storing collection of rows */ using RowCollection = internals::ThreadSafeDeque; - namespace internals { + namespace internals + { /** Abstract base class which provides CSV parsing logic. * * Concrete implementations may customize this logic across * different input sources, such as memory mapped files, stringstreams, * etc... */ - class IBasicCSVParser { + class IBasicCSVParser + { public: IBasicCSVParser() = default; IBasicCSVParser(const CSVFormat&, const ColNamesPtr&); - IBasicCSVParser(const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags - ) : _parse_flags(parse_flags), _ws_flags(ws_flags) {}; + IBasicCSVParser(const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags) + : _parse_flags(parse_flags) + , _ws_flags(ws_flags){}; - virtual ~IBasicCSVParser() {} + virtual ~IBasicCSVParser() + { + } /** Whether or not we have reached the end of source */ - bool eof() { return this->_eof; } + bool eof() + { + return this->_eof; + } /** Parse the next block of data */ virtual void next(size_t bytes) = 0; @@ -6034,18 +6225,26 @@ namespace csv { /** Indicate the last block of data has been parsed */ void end_feed(); - CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept { + CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept + { return _parse_flags.data()[ch + 128]; } - CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept { + CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept + { return quote_escape_flag(parse_flag(ch), this->quote_escape); } /** Whether or not this CSV has a UTF-8 byte order mark */ - CONSTEXPR bool utf8_bom() const { return this->_utf8_bom; } + CONSTEXPR bool utf8_bom() const + { + return this->_utf8_bom; + } - void set_output(RowCollection& rows) { this->_records = &rows; } + void set_output(RowCollection& rows) + { + this->_records = &rows; + } protected: /** @name Current Parser State */ @@ -6070,7 +6269,10 @@ namespace csv { ///@} /** Whether or not source needs to be read in chunks */ - CONSTEXPR bool no_chunk() const { return this->source_size < ITERATION_CHUNK_SIZE; } + CONSTEXPR bool no_chunk() const + { + return this->source_size < ITERATION_CHUNK_SIZE; + } /** Parse the current chunk of data * * @@ -6080,6 +6282,7 @@ namespace csv { /** Create a new RawCSVDataPtr for a new chunk of data */ void reset_data_ptr(); + private: /** An array where the (i + 128)th slot determines whether ASCII character i should * be trimmed @@ -6098,11 +6301,13 @@ namespace csv { /** Where complete rows should be pushed to */ RowCollection* _records = nullptr; - CONSTEXPR_17 bool ws_flag(const char ch) const noexcept { + CONSTEXPR_17 bool ws_flag(const char ch) const noexcept + { return _ws_flags.data()[ch + 128]; } - size_t& current_row_start() { + size_t& current_row_start() + { return this->current_row.data_start; } @@ -6122,32 +6327,33 @@ namespace csv { * or an `std::ifstream` */ template - class StreamParser: public IBasicCSVParser { + class StreamParser : public IBasicCSVParser + { using RowCollection = ThreadSafeDeque; public: - StreamParser(TStream& source, - const CSVFormat& format, - const ColNamesPtr& col_names = nullptr - ) : IBasicCSVParser(format, col_names), _source(std::move(source)) {}; + StreamParser(TStream& source, const CSVFormat& format, const ColNamesPtr& col_names = nullptr) + : IBasicCSVParser(format, col_names) + , _source(std::move(source)){}; - StreamParser( - TStream& source, - internals::ParseFlagMap parse_flags, - internals::WhitespaceMap ws_flags) : - IBasicCSVParser(parse_flags, ws_flags), - _source(std::move(source)) - {}; + StreamParser(TStream& source, internals::ParseFlagMap parse_flags, internals::WhitespaceMap ws_flags) + : IBasicCSVParser(parse_flags, ws_flags) + , _source(std::move(source)){}; - ~StreamParser() {} + ~StreamParser() + { + } - void next(size_t bytes = ITERATION_CHUNK_SIZE) override { - if (this->eof()) return; + void next(size_t bytes = ITERATION_CHUNK_SIZE) override + { + if (this->eof()) + return; this->reset_data_ptr(); this->data_ptr->_data = std::make_shared(); - if (source_size == 0) { + if (source_size == 0) + { const auto start = _source.tellg(); _source.seekg(0, std::ios::end); const auto end = _source.tellg(); @@ -6171,11 +6377,13 @@ namespace csv { this->current_row = CSVRow(this->data_ptr); size_t remainder = this->parse(); - if (stream_pos == source_size || no_chunk()) { + if (stream_pos == source_size || no_chunk()) + { this->_eof = true; this->end_feed(); } - else { + else + { this->stream_pos -= (length - remainder); } } @@ -6194,17 +6402,19 @@ namespace csv { * re-align each memory map to the beginning of a CSV row. * */ - class MmapParser : public IBasicCSVParser { + class MmapParser : public IBasicCSVParser + { public: - MmapParser(csv::string_view filename, - const CSVFormat& format, - const ColNamesPtr& col_names = nullptr - ) : IBasicCSVParser(format, col_names) { + MmapParser(csv::string_view filename, const CSVFormat& format, const ColNamesPtr& col_names = nullptr) + : IBasicCSVParser(format, col_names) + { this->_filename = filename.data(); this->source_size = get_file_size(filename); }; - ~MmapParser() {} + ~MmapParser() + { + } void next(size_t bytes) override; @@ -6212,19 +6422,21 @@ namespace csv { std::string _filename; size_t mmap_pos = 0; }; - } -} - + } // namespace internals +} // namespace csv /** The all encompassing namespace */ -namespace csv { +namespace csv +{ /** Stuff that is generally not of interest to end-users */ - namespace internals { + namespace internals + { std::string format_row(const std::vector& row, csv::string_view delim = ", "); - std::vector _get_col_names( csv::string_view head, const CSVFormat format = CSVFormat::guess_csv()); + std::vector _get_col_names(csv::string_view head, const CSVFormat format = CSVFormat::guess_csv()); - struct GuessScore { + struct GuessScore + { double score; size_t header; }; @@ -6232,15 +6444,12 @@ namespace csv { CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format); CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); - } + } // namespace internals - std::vector get_col_names( - csv::string_view filename, - const CSVFormat format = CSVFormat::guess_csv()); + std::vector get_col_names(csv::string_view filename, const CSVFormat format = CSVFormat::guess_csv()); /** Guess the delimiter used by a delimiter-separated values file */ - CSVGuessResult guess_format(csv::string_view filename, - const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); + CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); /** @class CSVReader * @brief Main class for parsing CSVs from files and in-memory sources @@ -6249,7 +6458,8 @@ namespace csv { * - By default, rows that are too short or too long are dropped * - Custom behavior can be defined by overriding bad_row_handler in a subclass */ - class CSVReader { + class CSVReader + { public: /** * An input iterator capable of handling large files. @@ -6261,48 +6471,61 @@ namespace csv { * @par Using with `` library * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 2 */ - class iterator { + class iterator + { public: - #ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVRow; using difference_type = std::ptrdiff_t; - using pointer = CSVRow * ; - using reference = CSVRow & ; + using pointer = CSVRow*; + using reference = CSVRow&; using iterator_category = std::input_iterator_tag; - #endif +#endif iterator() = default; - iterator(CSVReader* reader) : daddy(reader) {}; + iterator(CSVReader* reader) + : daddy(reader){}; iterator(CSVReader*, CSVRow&&); /** Access the CSVRow held by the iterator */ - CONSTEXPR_14 reference operator*() { return this->row; } + CONSTEXPR_14 reference operator*() + { + return this->row; + } /** Return a pointer to the CSVRow the iterator has stopped at */ - CONSTEXPR_14 pointer operator->() { return &(this->row); } + CONSTEXPR_14 pointer operator->() + { + return &(this->row); + } - iterator& operator++(); /**< Pre-increment iterator */ + iterator& operator++(); /**< Pre-increment iterator */ iterator operator++(int); /**< Post-increment ierator */ iterator& operator--(); /** Returns true if iterators were constructed from the same CSVReader * and point to the same row */ - CONSTEXPR bool operator==(const iterator& other) const noexcept { + CONSTEXPR bool operator==(const iterator& other) const noexcept + { return (this->daddy == other.daddy) && (this->i == other.i); } - CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } + CONSTEXPR bool operator!=(const iterator& other) const noexcept + { + return !operator==(other); + } + private: - CSVReader * daddy = nullptr; // Pointer to parent - CSVRow row; // Current row - size_t i = 0; // Index of current row + CSVReader* daddy = nullptr; // Pointer to parent + CSVRow row; // Current row + size_t i = 0; // Index of current row }; /** @name Constructors * Constructors for iterating over large files and parsing in-memory sources. */ - ///@{ + ///@{ CSVReader(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); /** Allows parsing stream sources such as `std::stringstream` or `std::ifstream` @@ -6311,38 +6534,43 @@ namespace csv { * @note Currently this constructor requires special CSV dialects to be manually * specified. */ - template::value, int> = 0> - CSVReader(TStream& source, CSVFormat format = CSVFormat()) : _format(format) { + template::value, int> = 0> + CSVReader(TStream& source, CSVFormat format = CSVFormat()) + : _format(format) + { using Parser = internals::StreamParser; if (!format.col_names.empty()) this->set_col_names(format.col_names); - this->parser = std::unique_ptr( - new Parser(source, format, col_names)); // For C++11 + this->parser = std::unique_ptr(new Parser(source, format, col_names)); // For C++11 this->initial_read(); } ///@} CSVReader(const CSVReader&) = delete; // No copy constructor - CSVReader(CSVReader&&) = default; // Move constructor + CSVReader(CSVReader&&) = default; // Move constructor CSVReader& operator=(const CSVReader&) = delete; // No copy assignment CSVReader& operator=(CSVReader&& other) = default; - ~CSVReader() { - if (this->read_csv_worker.joinable()) { + ~CSVReader() + { + if (this->read_csv_worker.joinable()) + { this->read_csv_worker.join(); } } /** @name Retrieving CSV Rows */ ///@{ - bool read_row(CSVRow &row); + bool read_row(CSVRow& row); iterator begin(); HEDLEY_CONST iterator end() const noexcept; /** Returns true if we have reached end of file */ - bool eof() const noexcept { return this->parser->eof(); }; + bool eof() const noexcept + { + return this->parser->eof(); + }; ///@} /** @name CSV Metadata */ @@ -6360,13 +6588,22 @@ namespace csv { * @note Gives an accurate answer regardless of when it is called. * */ - CONSTEXPR bool empty() const noexcept { return this->n_rows() == 0; } + CONSTEXPR bool empty() const noexcept + { + return this->n_rows() == 0; + } /** Retrieves the number of rows that have been read so far */ - CONSTEXPR size_t n_rows() const noexcept { return this->_n_rows; } + CONSTEXPR size_t n_rows() const noexcept + { + return this->_n_rows; + } /** Whether or not CSV was prefixed with a UTF-8 bom */ - bool utf8_bom() const noexcept { return this->parser->utf8_bom(); } + bool utf8_bom() const noexcept + { + return this->parser->utf8_bom(); + } ///@} protected: @@ -6394,9 +6631,9 @@ namespace csv { std::unique_ptr parser = nullptr; /** Queue of parsed CSV rows */ - std::unique_ptr records{new RowCollection(100)}; + std::unique_ptr records{ new RowCollection(100) }; - size_t n_cols = 0; /**< The number of columns in this CSV */ + size_t n_cols = 0; /**< The number of columns in this CSV */ size_t _n_rows = 0; /**< How many rows (minus header) have been read so far */ /** @name Multi-Threaded File Reading Functions */ @@ -6416,31 +6653,34 @@ namespace csv { ///@} /** Read initial chunk to get metadata */ - void initial_read() { + void initial_read() + { this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); this->read_csv_worker.join(); } void trim_header(); }; -} +} // namespace csv /** @file * Calculates statistics from CSV files */ -#include #include +#include #include -namespace csv { +namespace csv +{ /** Class for calculating statistics from CSV files and in-memory sources * * **Example** * \include programs/csv_stats.cpp * */ - class CSVStat { + class CSVStat + { public: using FreqCount = std::unordered_map; using TypeCount = std::unordered_map; @@ -6452,12 +6692,14 @@ namespace csv { std::vector get_counts() const; std::vector get_dtypes() const; - std::vector get_col_names() const { + std::vector get_col_names() const + { return this->reader.get_col_names(); } CSVStat(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); CSVStat(std::stringstream& source, CSVFormat format = CSVFormat()); + private: // An array of rolling averages // Each index corresponds to the rolling mean for the column at said index @@ -6482,28 +6724,30 @@ namespace csv { CSVReader reader; std::deque records = {}; }; -} +} // namespace csv #include #include #include -namespace csv { +namespace csv +{ /** Returned by get_file_info() */ - struct CSVFileInfo { - std::string filename; /**< Filename */ + struct CSVFileInfo + { + std::string filename; /**< Filename */ std::vector col_names; /**< CSV column names */ - char delim; /**< Delimiting character */ - size_t n_rows; /**< Number of rows in a file */ - size_t n_cols; /**< Number of columns in a CSV */ + char delim; /**< Delimiting character */ + size_t n_rows; /**< Number of rows in a file */ + size_t n_cols; /**< Number of columns in a CSV */ }; /** @name Shorthand Parsing Functions * @brief Convienience functions for parsing small strings */ - ///@{ - CSVReader operator ""_csv(const char*, size_t); - CSVReader operator ""_csv_no_header(const char*, size_t); + ///@{ + CSVReader operator""_csv(const char*, size_t); + CSVReader operator""_csv_no_header(const char*, size_t); CSVReader parse(csv::string_view in, CSVFormat format = CSVFormat()); CSVReader parse_no_header(csv::string_view in); ///@} @@ -6512,13 +6756,12 @@ namespace csv { ///@{ std::unordered_map csv_data_types(const std::string&); CSVFileInfo get_file_info(const std::string& filename); - int get_col_pos(csv::string_view filename, csv::string_view col_name, - const CSVFormat& format = CSVFormat::guess_csv()); + int get_col_pos(csv::string_view filename, csv::string_view col_name, const CSVFormat& format = CSVFormat::guess_csv()); ///@} -} +} // namespace csv /** @file - * A standalone header file for writing delimiter-separated files - */ + * A standalone header file for writing delimiter-separated files + */ #include #include @@ -6527,20 +6770,23 @@ namespace csv { #include #include - -namespace csv { - namespace internals { +namespace csv +{ + namespace internals + { static int DECIMAL_PLACES = 5; /** to_string() for unsigned integers */ - template::value, int> = 0> - inline std::string to_string(T value) { + template::value, int> = 0> + inline std::string to_string(T value) + { std::string digits_reverse = ""; - if (value == 0) return "0"; + if (value == 0) + return "0"; - while (value > 0) { + while (value > 0) + { digits_reverse += (char)('0' + (value % 10)); value /= 10; } @@ -6549,11 +6795,9 @@ namespace csv { } /** to_string() for signed integers */ - template< - typename T, - csv::enable_if_t::value && std::is_signed::value, int> = 0 - > - inline std::string to_string(T value) { + template::value && std::is_signed::value, int> = 0> + inline std::string to_string(T value) + { if (value >= 0) return to_string((size_t)value); @@ -6561,64 +6805,69 @@ namespace csv { } /** to_string() for floating point numbers */ - template< - typename T, - csv::enable_if_t::value, int> = 0 - > - inline std::string to_string(T value) { - std::string result; + template::value, int> = 0> + inline std::string to_string(T value) + { + std::string result; - T integral_part; - T fractional_part = std::abs(std::modf(value, &integral_part)); - integral_part = std::abs(integral_part); + T integral_part; + T fractional_part = std::abs(std::modf(value, &integral_part)); + integral_part = std::abs(integral_part); - // Integral part - if (value < 0) result = "-"; + // Integral part + if (value < 0) + result = "-"; - if (integral_part == 0) { - result = "0"; - } - else { - for (int n_digits = (int)(std::log(integral_part) / std::log(10)); - n_digits + 1 > 0; n_digits --) { - int digit = (int)(std::fmod(integral_part, pow10(n_digits + 1)) / pow10(n_digits)); - result += (char)('0' + digit); - } + if (integral_part == 0) + { + result = "0"; + } + else + { + for (int n_digits = (int)(std::log(integral_part) / std::log(10)); n_digits + 1 > 0; n_digits--) + { + int digit = (int)(std::fmod(integral_part, pow10(n_digits + 1)) / pow10(n_digits)); + result += (char)('0' + digit); } + } - // Decimal part - result += "."; + // Decimal part + result += "."; - if (fractional_part > 0) { - fractional_part *= (T)(pow10(DECIMAL_PLACES)); - for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) { - int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1)); - result += (char)('0' + digit); - } - } - else { - result += "0"; + if (fractional_part > 0) + { + fractional_part *= (T)(pow10(DECIMAL_PLACES)); + for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) + { + int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1)); + result += (char)('0' + digit); } + } + else + { + result += "0"; + } - return result; + return result; } - } + } // namespace internals /** Sets how many places after the decimal will be written for floating point numbers * * @param precision Number of decimal places */ - inline static void set_decimal_places(int precision) { + inline static void set_decimal_places(int precision) + { internals::DECIMAL_PLACES = precision; } /** @name CSV Writing */ ///@{ - /** + /** * Class for writing delimiter separated values files * * To write formatted strings, one should - * -# Initialize a DelimWriter with respect to some output stream + * -# Initialize a DelimWriter with respect to some output stream * -# Call write_row() on std::vectors of unformatted text * * @tparam OutputStream The output stream, e.g. `std::ofstream`, `std::stringstream` @@ -6640,27 +6889,31 @@ namespace csv { * @snippet test_write_csv.cpp CSV Writer Tuple Example */ template - class DelimWriter { + class DelimWriter + { public: /** Construct a DelimWriter over the specified output stream * * @param _out Stream to write to * @param _quote_minimal Limit field quoting to only when necessary - */ + */ DelimWriter(OutputStream& _out, bool _quote_minimal = true) - : out(_out), quote_minimal(_quote_minimal) {}; + : out(_out) + , quote_minimal(_quote_minimal){}; /** Construct a DelimWriter over the file * * @param[out] filename File to write to */ - DelimWriter(const std::string& filename) : DelimWriter(std::ifstream(filename)) {}; + DelimWriter(const std::string& filename) + : DelimWriter(std::ifstream(filename)){}; /** Destructor will flush remaining data * */ - ~DelimWriter() { + ~DelimWriter() + { out.flush(); } @@ -6673,10 +6926,13 @@ namespace csv { * @return The current DelimWriter instance (allowing for operator chaining) */ template - DelimWriter& operator<<(const std::array& record) { - for (size_t i = 0; i < Size; i++) { + DelimWriter& operator<<(const std::array& record) + { + for (size_t i = 0; i < Size; i++) + { out << csv_escape(record[i]); - if (i + 1 != Size) out << Delim; + if (i + 1 != Size) + out << Delim; } end_out(); @@ -6685,28 +6941,34 @@ namespace csv { /** @copydoc operator<< */ template - DelimWriter& operator<<(const std::tuple& record) { + DelimWriter& operator<<(const std::tuple& record) + { this->write_tuple<0, T...>(record); return *this; } /** * @tparam T A container such as std::vector, std::deque, or std::list - * + * * @copydoc operator<< */ template< - typename T, typename Alloc, template class Container, + typename T, + typename Alloc, + template + class Container, // Avoid conflicting with tuples with two elements - csv::enable_if_t::value, int> = 0 - > - DelimWriter& operator<<(const Container& record) { + csv::enable_if_t::value, int> = 0> + DelimWriter& operator<<(const Container& record) + { const size_t ilen = record.size(); size_t i = 0; - for (const auto& field : record) { + for (const auto& field : record) + { out << csv_escape(field); - if (i + 1 != ilen) out << Delim; + if (i + 1 != ilen) + out << Delim; i++; } @@ -6717,38 +6979,35 @@ namespace csv { /** Flushes the written data * */ - void flush() { + void flush() + { out.flush(); } private: template< typename T, - csv::enable_if_t< - !std::is_convertible::value - && !std::is_convertible::value - , int> = 0 - > - std::string csv_escape(T in) { + csv::enable_if_t::value && !std::is_convertible::value, int> = 0> + std::string csv_escape(T in) + { return internals::to_string(in); } template< typename T, - csv::enable_if_t< - std::is_convertible::value - || std::is_convertible::value - , int> = 0 - > - std::string csv_escape(T in) { - IF_CONSTEXPR(std::is_convertible::value) { + csv::enable_if_t::value || std::is_convertible::value, int> = 0> + std::string csv_escape(T in) + { + IF_CONSTEXPR(std::is_convertible::value) + { return _csv_escape(in); } - + return _csv_escape(std::string(in)); } - std::string _csv_escape(csv::string_view in) { + std::string _csv_escape(csv::string_view in) + { /** Format a string to be RFC 4180-compliant * @param[in] in String to be CSV-formatted * @param[out] quote_minimal Only quote fields if necessary. @@ -6758,16 +7017,21 @@ namespace csv { // Do we need a quote escape bool quote_escape = false; - for (auto ch : in) { - if (ch == Quote || ch == Delim || ch == '\r' || ch == '\n') { + for (auto ch : in) + { + if (ch == Quote || ch == Delim || ch == '\r' || ch == '\n') + { quote_escape = true; break; } } - if (!quote_escape) { - if (quote_minimal) return std::string(in); - else { + if (!quote_escape) + { + if (quote_minimal) + return std::string(in); + else + { std::string ret(1, Quote); ret += in.data(); ret += Quote; @@ -6777,9 +7041,12 @@ namespace csv { // Start initial quote escape sequence std::string ret(1, Quote); - for (auto ch: in) { - if (ch == Quote) ret += std::string(2, Quote); - else ret += ch; + for (auto ch : in) + { + if (ch == Quote) + ret += std::string(2, Quote); + else + ret += ch; } // Finish off quote escape @@ -6789,28 +7056,31 @@ namespace csv { /** Recurisve template for writing std::tuples */ template - typename std::enable_if::type write_tuple(const std::tuple& record) { + typename std::enable_if < Index::type write_tuple(const std::tuple& record) + { out << csv_escape(std::get(record)); - IF_CONSTEXPR (Index + 1 < sizeof...(T)) out << Delim; + IF_CONSTEXPR(Index + 1 < sizeof...(T)) out << Delim; this->write_tuple(record); } /** Base case for writing std::tuples */ template - typename std::enable_if::type write_tuple(const std::tuple& record) { + typename std::enable_if::type write_tuple(const std::tuple& record) + { (void)record; end_out(); } /** Ends a line in 'out' and flushes, if Flush is true.*/ - void end_out() { + void end_out() + { out << '\n'; IF_CONSTEXPR(Flush) out.flush(); } - OutputStream & out; + OutputStream& out; bool quote_minimal; }; @@ -6825,7 +7095,7 @@ namespace csv { using CSVWriter = DelimWriter; /** Class for writing tab-separated values files - * + * * @sa csv::DelimWriter::write_row() * @sa csv::DelimWriter::operator<<() * @@ -6837,34 +7107,40 @@ namespace csv { /** Return a csv::CSVWriter over the output stream */ template - inline CSVWriter make_csv_writer(OutputStream& out, bool quote_minimal=true) { + inline CSVWriter make_csv_writer(OutputStream& out, bool quote_minimal = true) + { return CSVWriter(out, quote_minimal); } /** Return a buffered csv::CSVWriter over the output stream (does not auto flush) */ template - inline CSVWriter make_csv_writer_buffered(OutputStream& out, bool quote_minimal=true) { + inline CSVWriter make_csv_writer_buffered(OutputStream& out, bool quote_minimal = true) + { return CSVWriter(out, quote_minimal); } /** Return a csv::TSVWriter over the output stream */ template - inline TSVWriter make_tsv_writer(OutputStream& out, bool quote_minimal=true) { + inline TSVWriter make_tsv_writer(OutputStream& out, bool quote_minimal = true) + { return TSVWriter(out, quote_minimal); } /** Return a buffered csv::TSVWriter over the output stream (does not auto flush) */ template - inline TSVWriter make_tsv_writer_buffered(OutputStream& out, bool quote_minimal=true) { + inline TSVWriter make_tsv_writer_buffered(OutputStream& out, bool quote_minimal = true) + { return TSVWriter(out, quote_minimal); } ///@} -} +} // namespace csv - -namespace csv { - namespace internals { - CSV_INLINE size_t get_file_size(csv::string_view filename) { +namespace csv +{ + namespace internals + { + CSV_INLINE size_t get_file_size(csv::string_view filename) + { std::ifstream infile(std::string(filename), std::ios::binary); const auto start = infile.tellg(); infile.seekg(0, std::ios::end); @@ -6873,18 +7149,21 @@ namespace csv { return end - start; } - CSV_INLINE std::string get_csv_head(csv::string_view filename) { + CSV_INLINE std::string get_csv_head(csv::string_view filename) + { return get_csv_head(filename, get_file_size(filename)); } - CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) { + CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) + { const size_t bytes = 500000; std::error_code error; size_t length = std::min((size_t)file_size, bytes); auto mmap = mio::make_mmap_source(std::string(filename), 0, length, error); - if (error) { + if (error) + { throw std::runtime_error("Cannot open file " + std::string(filename)); } @@ -6894,32 +7173,31 @@ namespace csv { #ifdef _MSC_VER #pragma region IBasicCVParser #endif - CSV_INLINE IBasicCSVParser::IBasicCSVParser( - const CSVFormat& format, - const ColNamesPtr& col_names - ) : _col_names(col_names) { - if (format.no_quote) { + CSV_INLINE IBasicCSVParser::IBasicCSVParser(const CSVFormat& format, const ColNamesPtr& col_names) + : _col_names(col_names) + { + if (format.no_quote) + { _parse_flags = internals::make_parse_flags(format.get_delim()); } - else { + else + { _parse_flags = internals::make_parse_flags(format.get_delim(), format.quote_char); } - _ws_flags = internals::make_ws_flags( - format.trim_chars.data(), format.trim_chars.size() - ); + _ws_flags = internals::make_ws_flags(format.trim_chars.data(), format.trim_chars.size()); } - CSV_INLINE void IBasicCSVParser::end_feed() { + CSV_INLINE void IBasicCSVParser::end_feed() + { using internals::ParseFlags; - bool empty_last_field = this->data_ptr - && this->data_ptr->_data - && !this->data_ptr->data.empty() - && parse_flag(this->data_ptr->data.back()) == ParseFlags::DELIMITER; + bool empty_last_field = this->data_ptr && this->data_ptr->_data && !this->data_ptr->data.empty() && + parse_flag(this->data_ptr->data.back()) == ParseFlags::DELIMITER; // Push field - if (this->field_length > 0 || empty_last_field) { + if (this->field_length > 0 || empty_last_field) + { this->push_field(); } @@ -6928,7 +7206,8 @@ namespace csv { this->push_row(); } - CSV_INLINE void IBasicCSVParser::parse_field() noexcept { + CSV_INLINE void IBasicCSVParser::parse_field() noexcept + { using internals::ParseFlags; auto& in = this->data_ptr->data; @@ -6956,20 +7235,14 @@ namespace csv { CSV_INLINE void IBasicCSVParser::push_field() { // Update - if (field_has_double_quote) { - fields->emplace_back( - field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, - field_length, - true - ); + if (field_has_double_quote) + { + fields->emplace_back(field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, field_length, true); field_has_double_quote = false; - } - else { - fields->emplace_back( - field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, - field_length - ); + else + { + fields->emplace_back(field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, field_length); } current_row.row_length++; @@ -6990,8 +7263,10 @@ namespace csv { this->trim_utf8_bom(); auto& in = this->data_ptr->data; - while (this->data_pos < in.size()) { - switch (compound_parse_flag(in[this->data_pos])) { + while (this->data_pos < in.size()) + { + switch (compound_parse_flag(in[this->data_pos])) + { case ParseFlags::DELIMITER: this->push_field(); this->data_pos++; @@ -7017,15 +7292,19 @@ namespace csv { break; case ParseFlags::QUOTE_ESCAPE_QUOTE: - if (data_pos + 1 == in.size()) return this->current_row_start(); - else if (data_pos + 1 < in.size()) { + if (data_pos + 1 == in.size()) + return this->current_row_start(); + else if (data_pos + 1 < in.size()) + { auto next_ch = parse_flag(in[data_pos + 1]); - if (next_ch >= ParseFlags::DELIMITER) { + if (next_ch >= ParseFlags::DELIMITER) + { quote_escape = false; data_pos++; break; } - else if (next_ch == ParseFlags::QUOTE) { + else if (next_ch == ParseFlags::QUOTE) + { // Case: Escaped quote data_pos += 2; this->field_length += 2; @@ -7033,7 +7312,7 @@ namespace csv { break; } } - + // Case: Unescaped single quote => not strictly valid but we'll keep it this->field_length++; data_pos++; @@ -7041,7 +7320,8 @@ namespace csv { break; default: // Quote (currently not quote escaped) - if (this->field_length == 0) { + if (this->field_length == 0) + { quote_escape = true; data_pos++; if (field_start == UNINITIALIZED_FIELD && data_pos < in.size() && !ws_flag(in[data_pos])) @@ -7060,23 +7340,28 @@ namespace csv { return this->current_row_start(); } - CSV_INLINE void IBasicCSVParser::push_row() { + CSV_INLINE void IBasicCSVParser::push_row() + { current_row.row_length = fields->size() - current_row.fields_start; this->_records->push_back(std::move(current_row)); } - CSV_INLINE void IBasicCSVParser::reset_data_ptr() { + CSV_INLINE void IBasicCSVParser::reset_data_ptr() + { this->data_ptr = std::make_shared(); this->data_ptr->parse_flags = this->_parse_flags; this->data_ptr->col_names = this->_col_names; this->fields = &(this->data_ptr->fields); } - CSV_INLINE void IBasicCSVParser::trim_utf8_bom() { + CSV_INLINE void IBasicCSVParser::trim_utf8_bom() + { auto& data = this->data_ptr->data; - if (!this->unicode_bom_scan && data.size() >= 3) { - if (data[0] == '\xEF' && data[1] == '\xBB' && data[2] == '\xBF') { + if (!this->unicode_bom_scan && data.size() >= 3) + { + if (data[0] == '\xEF' && data[1] == '\xBB' && data[2] == '\xBF') + { this->data_pos += 3; // Remove BOM from input string this->_utf8_bom = true; } @@ -7091,7 +7376,8 @@ namespace csv { #ifdef _MSC_VER #pragma region Specializations #endif - CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) { + CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) + { // Reset parser state this->field_start = UNINITIALIZED_FIELD; this->field_length = 0; @@ -7100,9 +7386,11 @@ namespace csv { // Create memory map size_t length = std::min(this->source_size - this->mmap_pos, bytes); std::error_code error; - this->data_ptr->_data = std::make_shared>(mio::make_mmap_source(this->_filename, this->mmap_pos, length, error)); + this->data_ptr->_data = + std::make_shared>(mio::make_mmap_source(this->_filename, this->mmap_pos, length, error)); this->mmap_pos += length; - if (error) throw error; + if (error) + throw error; auto mmap_ptr = (mio::basic_mmap_source*)(this->data_ptr->_data.get()); @@ -7111,9 +7399,10 @@ namespace csv { // Parse this->current_row = CSVRow(this->data_ptr); - size_t remainder = this->parse(); + size_t remainder = this->parse(); - if (this->mmap_pos == this->source_size || no_chunk()) { + if (this->mmap_pos == this->source_size || no_chunk()) + { this->_eof = true; this->end_feed(); } @@ -7123,25 +7412,30 @@ namespace csv { #ifdef _MSC_VER #pragma endregion #endif - } -} + } // namespace internals +} // namespace csv - -namespace csv { - namespace internals { - CSV_INLINE std::vector ColNames::get_col_names() const { +namespace csv +{ + namespace internals + { + CSV_INLINE std::vector ColNames::get_col_names() const + { return this->col_names; } - CSV_INLINE void ColNames::set_col_names(const std::vector& cnames) { + CSV_INLINE void ColNames::set_col_names(const std::vector& cnames) + { this->col_names = cnames; - for (size_t i = 0; i < cnames.size(); i++) { + for (size_t i = 0; i < cnames.size(); i++) + { this->col_pos[cnames[i]] = i; } } - CSV_INLINE int ColNames::index_of(csv::string_view col_name) const { + CSV_INLINE int ColNames::index_of(csv::string_view col_name) const + { auto pos = this->col_pos.find(col_name.data()); if (pos != this->col_pos.end()) return (int)pos->second; @@ -7149,12 +7443,13 @@ namespace csv { return CSV_NOT_FOUND; } - CSV_INLINE size_t ColNames::size() const noexcept { + CSV_INLINE size_t ColNames::size() const noexcept + { return this->col_names.size(); } - } -} + } // namespace internals +} // namespace csv /** @file * Defines an object used to store CSV format settings */ @@ -7162,41 +7457,48 @@ namespace csv { #include #include - -namespace csv { - CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) { +namespace csv +{ + CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) + { this->possible_delimiters = { delim }; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector & delim) { + CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector& delim) + { this->possible_delimiters = delim; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::quote(char quote) { + CSV_INLINE CSVFormat& CSVFormat::quote(char quote) + { this->no_quote = false; this->quote_char = quote; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector & chars) { + CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector& chars) + { this->trim_chars = chars; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector& names) { + CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector& names) + { this->col_names = names; this->header = -1; return *this; } - CSV_INLINE CSVFormat& CSVFormat::header_row(int row) { - if (row < 0) this->variable_column_policy = VariableColumnPolicy::KEEP; + CSV_INLINE CSVFormat& CSVFormat::header_row(int row) + { + if (row < 0) + this->variable_column_policy = VariableColumnPolicy::KEEP; this->header = row; this->col_names = {}; @@ -7205,35 +7507,32 @@ namespace csv { CSV_INLINE void CSVFormat::assert_no_char_overlap() { - auto delims = std::set( - this->possible_delimiters.begin(), this->possible_delimiters.end()), - trims = std::set( - this->trim_chars.begin(), this->trim_chars.end()); + auto delims = std::set(this->possible_delimiters.begin(), this->possible_delimiters.end()), + trims = std::set(this->trim_chars.begin(), this->trim_chars.end()); // Stores intersection of possible delimiters and trim characters std::vector intersection = {}; // Find which characters overlap, if any - std::set_intersection( - delims.begin(), delims.end(), - trims.begin(), trims.end(), - std::back_inserter(intersection)); + std::set_intersection(delims.begin(), delims.end(), trims.begin(), trims.end(), std::back_inserter(intersection)); // Make sure quote character is not contained in possible delimiters // or whitespace characters - if (delims.find(this->quote_char) != delims.end() || - trims.find(this->quote_char) != trims.end()) { + if (delims.find(this->quote_char) != delims.end() || trims.find(this->quote_char) != trims.end()) + { intersection.push_back(this->quote_char); } - if (!intersection.empty()) { + if (!intersection.empty()) + { std::string err_msg = "There should be no overlap between the quote character, " - "the set of possible delimiters " - "and the set of whitespace characters. Offending characters: "; + "the set of possible delimiters " + "and the set of whitespace characters. Offending characters: "; // Create a pretty error message with the list of overlapping // characters - for (size_t i = 0; i < intersection.size(); i++) { + for (size_t i = 0; i < intersection.size(); i++) + { err_msg += "'"; err_msg += intersection[i]; err_msg += "'"; @@ -7245,21 +7544,26 @@ namespace csv { throw std::runtime_error(err_msg + '.'); } } -} +} // namespace csv /** @file * @brief Defines functionality needed for basic CSV parsing */ - -namespace csv { - namespace internals { - CSV_INLINE std::string format_row(const std::vector& row, csv::string_view delim) { +namespace csv +{ + namespace internals + { + CSV_INLINE std::string format_row(const std::vector& row, csv::string_view delim) + { /** Print a CSV row */ std::stringstream ret; - for (size_t i = 0; i < row.size(); i++) { + for (size_t i = 0; i < row.size(); i++) + { ret << row[i]; - if (i + 1 < row.size()) ret << delim; - else ret << '\n'; + if (i + 1 < row.size()) + ret << delim; + else + ret << '\n'; } ret.flush(); @@ -7272,7 +7576,8 @@ namespace csv { * @param[in] format Format of the CSV file * */ - CSV_INLINE std::vector _get_col_names(csv::string_view head, CSVFormat format) { + CSV_INLINE std::vector _get_col_names(csv::string_view head, CSVFormat format) + { // Parse the CSV auto trim_chars = format.get_trim_chars(); std::stringstream source(head.data()); @@ -7285,7 +7590,8 @@ namespace csv { return CSVRow(std::move(rows[format.get_header()])); } - CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format) { + CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format) + { // Frequency counter of row length std::unordered_map row_tally = { { 0, 0 } }; @@ -7300,15 +7606,19 @@ namespace csv { parser.set_output(rows); parser.next(); - for (size_t i = 0; i < rows.size(); i++) { + for (size_t i = 0; i < rows.size(); i++) + { auto& row = rows[i]; // Ignore zero-length rows - if (row.size() > 0) { - if (row_tally.find(row.size()) != row_tally.end()) { + if (row.size() > 0) + { + if (row_tally.find(row.size()) != row_tally.end()) + { row_tally[row.size()]++; } - else { + else + { row_tally[row.size()] = 1; row_when[row.size()] = i; } @@ -7320,24 +7630,24 @@ namespace csv { // Final score is equal to the largest // row size times rows of that size - for (auto& pair : row_tally) { + for (auto& pair : row_tally) + { auto row_size = pair.first; auto row_count = pair.second; double score = (double)(row_size * row_count); - if (score > final_score) { + if (score > final_score) + { final_score = score; header_row = row_when[row_size]; } } - return { - final_score, - header_row - }; + return { final_score, header_row }; } /** Guess the delimiter used by a delimiter-separated values file */ - CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims) { + CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims) + { /** For each delimiter, find out which row length was most common. * The delimiter with the longest mode row length wins. * Then, the line number of the header row is the first row with @@ -7345,14 +7655,15 @@ namespace csv { */ CSVFormat format; - size_t max_score = 0, - header = 0; + size_t max_score = 0, header = 0; char current_delim = delims[0]; - for (char cand_delim : delims) { + for (char cand_delim : delims) + { auto result = calculate_score(head, format.delimiter(cand_delim)); - if ((size_t)result.score > max_score) { + if ((size_t)result.score > max_score) + { max_score = (size_t)result.score; current_delim = cand_delim; header = result.header; @@ -7361,7 +7672,7 @@ namespace csv { return { current_delim, (int)header }; } - } + } // namespace internals /** Return a CSV's column names * @@ -7369,11 +7680,13 @@ namespace csv { * @param[in] format Format of the CSV file * */ - CSV_INLINE std::vector get_col_names(csv::string_view filename, CSVFormat format) { + CSV_INLINE std::vector get_col_names(csv::string_view filename, CSVFormat format) + { auto head = internals::get_csv_head(filename); /** Guess delimiter and header row */ - if (format.guess_delim()) { + if (format.guess_delim()) + { auto guess_result = guess_format(filename, format.get_possible_delims()); format.delimiter(guess_result.delim).header_row(guess_result.header_row); } @@ -7382,7 +7695,8 @@ namespace csv { } /** Guess the delimiter used by a delimiter-separated values file */ - CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims) { + CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims) + { auto head = internals::get_csv_head(filename); return internals::_guess_format(head, delims); } @@ -7398,12 +7712,15 @@ namespace csv { * \snippet tests/test_read_csv.cpp CSVField Example * */ - CSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) : _format(format) { + CSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) + : _format(format) + { auto head = internals::get_csv_head(filename); using Parser = internals::MmapParser; /** Guess delimiter and header row */ - if (format.guess_delim()) { + if (format.guess_delim()) + { auto guess_result = internals::_guess_format(head, format.possible_delimiters); format.delimiter(guess_result.delim); format.header = guess_result.header_row; @@ -7418,7 +7735,8 @@ namespace csv { } /** Return the format of the original raw CSV */ - CSV_INLINE CSVFormat CSVReader::get_format() const { + CSV_INLINE CSVFormat CSVReader::get_format() const + { CSVFormat new_format = this->_format; // Since users are normally not allowed to set @@ -7431,8 +7749,10 @@ namespace csv { } /** Return the CSV's column names as a vector of strings. */ - CSV_INLINE std::vector CSVReader::get_col_names() const { - if (this->col_names) { + CSV_INLINE std::vector CSVReader::get_col_names() const + { + if (this->col_names) + { return this->col_names->get_col_names(); } @@ -7442,21 +7762,28 @@ namespace csv { /** Return the index of the column name if found or * csv::CSV_NOT_FOUND otherwise. */ - CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const { + CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const + { auto _col_names = this->get_col_names(); for (size_t i = 0; i < _col_names.size(); i++) - if (_col_names[i] == col_name) return (int)i; + if (_col_names[i] == col_name) + return (int)i; return CSV_NOT_FOUND; } - CSV_INLINE void CSVReader::trim_header() { - if (!this->header_trimmed) { - for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) { - if (i == this->_format.header && this->col_names->empty()) { + CSV_INLINE void CSVReader::trim_header() + { + if (!this->header_trimmed) + { + for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) + { + if (i == this->_format.header && this->col_names->empty()) + { this->set_col_names(this->records->pop_front()); } - else { + else + { this->records->pop_front(); } } @@ -7485,14 +7812,16 @@ namespace csv { * @see CSVReader::read_csv_worker * @see CSVReader::read_row() */ - CSV_INLINE bool CSVReader::read_csv(size_t bytes) { + CSV_INLINE bool CSVReader::read_csv(size_t bytes) + { // Tell read_row() to listen for CSV rows this->records->notify_all(); this->parser->set_output(*this->records); this->parser->next(bytes); - if (!this->header_trimmed) { + if (!this->header_trimmed) + { this->trim_header(); } @@ -7516,16 +7845,20 @@ namespace csv { * \snippet tests/test_read_csv.cpp CSVField Example * */ - CSV_INLINE bool CSVReader::read_row(CSVRow &row) { - while (true) { - if (this->records->empty()) { + CSV_INLINE bool CSVReader::read_row(CSVRow& row) + { + while (true) + { + if (this->records->empty()) + { if (this->records->is_waitable()) // Reading thread is currently active => wait for it to populate records this->records->wait(); else if (this->parser->eof()) // End of file and no more records return false; - else { + else + { // Reading thread is not active => start another one if (this->read_csv_worker.joinable()) this->read_csv_worker.join(); @@ -7533,18 +7866,20 @@ namespace csv { this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); } } - else if (this->records->front().size() != this->n_cols && - this->_format.variable_column_policy != VariableColumnPolicy::KEEP) { + else if (this->records->front().size() != this->n_cols && this->_format.variable_column_policy != VariableColumnPolicy::KEEP) + { auto errored_row = this->records->pop_front(); - if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) { + if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) + { if (errored_row.size() < this->n_cols) throw std::runtime_error("Line too short " + internals::format_row(errored_row)); throw std::runtime_error("Line too long " + internals::format_row(errored_row)); } } - else { + else + { row = this->records->pop_front(); this->_n_rows++; return true; @@ -7553,22 +7888,25 @@ namespace csv { return false; } -} +} // namespace csv /** @file * Defines an input iterator for csv::CSVReader */ - -namespace csv { +namespace csv +{ /** Return an iterator to the first row in the reader */ - CSV_INLINE CSVReader::iterator CSVReader::begin() { - if (this->records->empty()) { + CSV_INLINE CSVReader::iterator CSVReader::begin() + { + if (this->records->empty()) + { this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); this->read_csv_worker.join(); // Still empty => return end iterator - if (this->records->empty()) return this->end(); + if (this->records->empty()) + return this->end(); } CSVReader::iterator ret(this, this->records->pop_front()); @@ -7578,7 +7916,8 @@ namespace csv { /** A placeholder for the imaginary past the end row in a CSV. * Attempting to deference this will lead to bad things. */ - CSV_INLINE HEDLEY_CONST CSVReader::iterator CSVReader::end() const noexcept { + CSV_INLINE HEDLEY_CONST CSVReader::iterator CSVReader::end() const noexcept + { return CSVReader::iterator(); } @@ -7586,8 +7925,9 @@ namespace csv { // CSVReader::iterator // ///////////////////////// - CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) : - daddy(_daddy) { + CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) + : daddy(_daddy) + { row = std::move(_row); } @@ -7598,8 +7938,10 @@ namespace csv { * @note This iterator does **not** block the thread responsible for parsing CSV. * */ - CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() { - if (!daddy->read_row(this->row)) { + CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() + { + if (!daddy->read_row(this->row)) + { this->daddy = nullptr; // this == end() } @@ -7607,15 +7949,17 @@ namespace csv { } /** Post-increment iterator */ - CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) { + CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) + { auto temp = *this; - if (!daddy->read_row(this->row)) { + if (!daddy->read_row(this->row)) + { this->daddy = nullptr; // this == end() } return temp; } -} +} // namespace csv /** @file * Defines the data type used for storing information about a CSV row @@ -7624,21 +7968,25 @@ namespace csv { #include #include -namespace csv { - namespace internals { - CSV_INLINE RawCSVField& CSVFieldList::operator[](size_t n) const { +namespace csv +{ + namespace internals + { + CSV_INLINE RawCSVField& CSVFieldList::operator[](size_t n) const + { const size_t page_no = n / _single_buffer_capacity; const size_t buffer_idx = (page_no < 1) ? n : n % _single_buffer_capacity; return this->buffers[page_no][buffer_idx]; } - CSV_INLINE void CSVFieldList::allocate() { - RawCSVField * buffer = new RawCSVField[_single_buffer_capacity]; + CSV_INLINE void CSVFieldList::allocate() + { + RawCSVField* buffer = new RawCSVField[_single_buffer_capacity]; buffers.push_back(buffer); _current_buffer_size = 0; _back = &(buffers.back()[0]); } - } + } // namespace internals /** Return a CSVField object corrsponding to the nth value in the row. * @@ -7649,7 +7997,8 @@ namespace csv { * Constant, by calling csv::CSVRow::get_csv::string_view() * */ - CSV_INLINE CSVField CSVRow::operator[](size_t n) const { + CSV_INLINE CSVField CSVRow::operator[](size_t n) const + { return CSVField(this->get_field(n)); } @@ -7662,17 +8011,20 @@ namespace csv { * * @param[in] col_name The column to look for */ - CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const { - auto & col_names = this->data->col_names; + CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const + { + auto& col_names = this->data->col_names; auto col_pos = col_names->index_of(col_name); - if (col_pos > -1) { + if (col_pos > -1) + { return this->operator[](col_pos); } throw std::runtime_error("Can't find a column named " + col_name); } - CSV_INLINE CSVRow::operator std::vector() const { + CSV_INLINE CSVRow::operator std::vector() const + { std::vector ret; for (size_t i = 0; i < size(); i++) ret.push_back(std::string(this->get_field(i))); @@ -7691,17 +8043,23 @@ namespace csv { auto& field = this->data->fields[field_index]; auto field_str = csv::string_view(this->data->data).substr(this->data_start + field.start); - if (field.has_double_quote) { + if (field.has_double_quote) + { auto& value = this->data->double_quote_fields[field_index]; - if (value.empty()) { + if (value.empty()) + { bool prev_ch_quote = false; - for (size_t i = 0; i < field.length; i++) { - if (this->data->parse_flags[field_str[i] + 128] == ParseFlags::QUOTE) { - if (prev_ch_quote) { + for (size_t i = 0; i < field.length; i++) + { + if (this->data->parse_flags[field_str[i] + 128] == ParseFlags::QUOTE) + { + if (prev_ch_quote) + { prev_ch_quote = false; continue; } - else { + else + { prev_ch_quote = true; } } @@ -7716,24 +8074,30 @@ namespace csv { return field_str.substr(0, field.length); } - CSV_INLINE bool CSVField::try_parse_hex(int& parsedValue) { + CSV_INLINE bool CSVField::try_parse_hex(int& parsedValue) + { size_t start = 0, end = 0; // Trim out whitespace chars - for (; start < this->sv.size() && this->sv[start] == ' '; start++); - for (end = start; end < this->sv.size() && this->sv[end] != ' '; end++); - + for (; start < this->sv.size() && this->sv[start] == ' '; start++) + ; + for (end = start; end < this->sv.size() && this->sv[end] != ' '; end++) + ; + unsigned long long int value = 0; size_t digits = (end - start); size_t base16_exponent = digits - 1; - if (digits == 0) return false; + if (digits == 0) + return false; - for (const auto& ch : this->sv.substr(start, digits)) { + for (const auto& ch : this->sv.substr(start, digits)) + { int digit = 0; - switch (ch) { + switch (ch) + { case '0': case '1': case '2': @@ -7786,7 +8150,8 @@ namespace csv { #pragma region CSVRow Iterator #endif /** Return an iterator pointing to the first field. */ - CSV_INLINE CSVRow::iterator CSVRow::begin() const { + CSV_INLINE CSVRow::iterator CSVRow::begin() const + { return CSVRow::iterator(this, 0); } @@ -7795,94 +8160,103 @@ namespace csv { * @warning Attempting to dereference the end iterator results * in dereferencing a null pointer. */ - CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept { + CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept + { return CSVRow::iterator(this, (int)this->size()); } - CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept { + CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept + { return std::reverse_iterator(this->end()); } - CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const { + CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const + { return std::reverse_iterator(this->begin()); } - CSV_INLINE HEDLEY_NON_NULL(2) - CSVRow::iterator::iterator(const CSVRow* _reader, int _i) - : daddy(_reader), i(_i) { + CSV_INLINE HEDLEY_NON_NULL(2) CSVRow::iterator::iterator(const CSVRow* _reader, int _i) + : daddy(_reader) + , i(_i) + { if (_i < (int)this->daddy->size()) - this->field = std::make_shared( - this->daddy->operator[](_i)); + this->field = std::make_shared(this->daddy->operator[](_i)); else this->field = nullptr; } - CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const { + CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const + { return *(this->field.get()); } - CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const { - // Using CSVField * as pointer type causes segfaults in MSVC debug builds - #ifdef _MSC_BUILD + CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const + { +// Using CSVField * as pointer type causes segfaults in MSVC debug builds +#ifdef _MSC_BUILD return this->field; - #else +#else return this->field.get(); - #endif +#endif } - CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() { + CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() + { // Pre-increment operator this->i++; if (this->i < (int)this->daddy->size()) - this->field = std::make_shared( - this->daddy->operator[](i)); + this->field = std::make_shared(this->daddy->operator[](i)); else // Reached the end of row this->field = nullptr; return *this; } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) + { // Post-increment operator auto temp = *this; this->operator++(); return temp; } - CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() { + CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() + { // Pre-decrement operator this->i--; - this->field = std::make_shared( - this->daddy->operator[](this->i)); + this->field = std::make_shared(this->daddy->operator[](this->i)); return *this; } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) + { // Post-decrement operator auto temp = *this; this->operator--(); return temp; } - - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const { + + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const + { // Allows for iterator arithmetic return CSVRow::iterator(this->daddy, i + (int)n); } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const + { // Allows for iterator arithmetic return CSVRow::iterator::operator+(-n); } #ifdef _MSC_VER #pragma endregion CSVRow Iterator #endif -} +} // namespace csv /** @file * Implements JSON serialization abilities */ - -namespace csv { +namespace csv +{ /* The implementations for json_extra_space() and json_escape_string() were modified from source code for JSON for Modern C++. @@ -7891,9 +8265,9 @@ namespace csv { The code is licensed under the [MIT License](http://opensource.org/licenses/MIT): - + Copyright © 2013-2015 Niels Lohmann. - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, @@ -7901,10 +8275,10 @@ namespace csv { publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -7915,7 +8289,8 @@ namespace csv { SOFTWARE. */ - namespace internals { + namespace internals + { /*! @brief calculates the extra space to escape a JSON string @@ -7928,7 +8303,6 @@ namespace csv { { std::size_t result = 0; - for (const auto& c : s) { switch (c) @@ -7940,26 +8314,24 @@ namespace csv { case '\n': case '\r': case '\t': - { - // from c (1 byte) to \x (2 bytes) - result += 1; - break; - } - + { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } default: - { - if (c >= 0x00 && c <= 0x1f) { - // from c (1 byte) to \uxxxx (6 bytes) - result += 5; + if (c >= 0x00 && c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + result += 5; + } + break; } - break; - } } } - return result; } @@ -7981,90 +8353,83 @@ namespace csv { { // quotation mark (0x22) case '"': - { - result[pos + 1] = '"'; - pos += 2; - break; - } - + { + result[pos + 1] = '"'; + pos += 2; + break; + } // reverse solidus (0x5c) case '\\': - { - // nothing to change - pos += 2; - break; - } - + { + // nothing to change + pos += 2; + break; + } // backspace (0x08) case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - + { + result[pos + 1] = 'b'; + pos += 2; + break; + } // formfeed (0x0c) case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - + { + result[pos + 1] = 'f'; + pos += 2; + break; + } // newline (0x0a) case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - + { + result[pos + 1] = 'n'; + pos += 2; + break; + } // carriage return (0x0d) case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - + { + result[pos + 1] = 'r'; + pos += 2; + break; + } // horizontal tab (0x09) case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - - default: - { - if (c >= 0x00 && c <= 0x1f) { - // print character c as \uxxxx - sprintf(&result[pos + 1], "u%04x", int(c)); - pos += 6; - // overwrite trailing null character - result[pos] = '\\'; + result[pos + 1] = 't'; + pos += 2; + break; } - else + + default: { - // all other characters are added as-is - result[pos++] = c; + if (c >= 0x00 && c <= 0x1f) + { + // print character c as \uxxxx + sprintf(&result[pos + 1], "u%04x", int(c)); + pos += 6; + // overwrite trailing null character + result[pos] = '\\'; + } + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; } - break; - } } } return result; } - } + } // namespace internals /** Convert a CSV row to a JSON object, i.e. * `{"col1":"value1","col2":"value2"}` @@ -8073,16 +8438,19 @@ namespace csv { * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for original columns. */ - CSV_INLINE std::string CSVRow::to_json(const std::vector& subset) const { + CSV_INLINE std::string CSVRow::to_json(const std::vector& subset) const + { std::vector col_names = subset; - if (subset.empty()) { + if (subset.empty()) + { col_names = this->data ? this->get_col_names() : std::vector({}); } const size_t _n_cols = col_names.size(); std::string ret = "{"; - - for (size_t i = 0; i < _n_cols; i++) { + + for (size_t i = 0; i < _n_cols; i++) + { auto& col = col_names[i]; auto field = this->operator[](col); @@ -8091,7 +8459,7 @@ namespace csv { // Add quotes around strings but not numbers if (field.is_num()) - ret += internals::json_escape_string(field.get()); + ret += internals::json_escape_string(field.get()); else ret += '"' + internals::json_escape_string(field.get()) + '"'; @@ -8111,7 +8479,8 @@ namespace csv { * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for all columns. */ - CSV_INLINE std::string CSVRow::to_json_array(const std::vector& subset) const { + CSV_INLINE std::string CSVRow::to_json_array(const std::vector& subset) const + { std::vector col_names = subset; if (subset.empty()) col_names = this->data ? this->get_col_names() : std::vector({}); @@ -8119,7 +8488,8 @@ namespace csv { const size_t _n_cols = col_names.size(); std::string ret = "["; - for (size_t i = 0; i < _n_cols; i++) { + for (size_t i = 0; i < _n_cols; i++) + { auto field = this->operator[](col_names[i]); // Add quotes around strings but not numbers @@ -8136,88 +8506,106 @@ namespace csv { ret += ']'; return ret; } -} +} // namespace csv /** @file * Calculates statistics from CSV files */ #include -namespace csv { +namespace csv +{ /** Calculate statistics for an arbitrarily large file. When this constructor * is called, CSVStat will process the entire file iteratively. Once finished, * methods like get_mean(), get_counts(), etc... can be used to retrieve statistics. */ - CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) : - reader(filename, format) { + CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) + : reader(filename, format) + { this->calc(); } /** Calculate statistics for a CSV stored in a std::stringstream */ - CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) : - reader(stream, format) { + CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) + : reader(stream, format) + { this->calc(); } /** Return current means */ - CSV_INLINE std::vector CSVStat::get_mean() const { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { + CSV_INLINE std::vector CSVStat::get_mean() const + { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) + { ret.push_back(this->rolling_means[i]); } return ret; } /** Return current variances */ - CSV_INLINE std::vector CSVStat::get_variance() const { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { - ret.push_back(this->rolling_vars[i]/(this->n[i] - 1)); + CSV_INLINE std::vector CSVStat::get_variance() const + { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) + { + ret.push_back(this->rolling_vars[i] / (this->n[i] - 1)); } return ret; } /** Return current mins */ - CSV_INLINE std::vector CSVStat::get_mins() const { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { + CSV_INLINE std::vector CSVStat::get_mins() const + { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) + { ret.push_back(this->mins[i]); } return ret; } /** Return current maxes */ - CSV_INLINE std::vector CSVStat::get_maxes() const { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { + CSV_INLINE std::vector CSVStat::get_maxes() const + { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) + { ret.push_back(this->maxes[i]); } return ret; } /** Get counts for each column */ - CSV_INLINE std::vector CSVStat::get_counts() const { + CSV_INLINE std::vector CSVStat::get_counts() const + { std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { + for (size_t i = 0; i < this->get_col_names().size(); i++) + { ret.push_back(this->counts[i]); } return ret; } /** Get data type counts for each column */ - CSV_INLINE std::vector CSVStat::get_dtypes() const { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) { + CSV_INLINE std::vector CSVStat::get_dtypes() const + { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) + { ret.push_back(this->dtypes[i]); } return ret; } - CSV_INLINE void CSVStat::calc_chunk() { + CSV_INLINE void CSVStat::calc_chunk() + { /** Only create stats counters the first time **/ - if (dtypes.empty()) { + if (dtypes.empty()) + { /** Go through all records and calculate specified statistics */ - for (size_t i = 0; i < this->get_col_names().size(); i++) { + for (size_t i = 0; i < this->get_col_names().size(); i++) + { dtypes.push_back({}); counts.push_back({}); rolling_means.push_back(0); @@ -8240,33 +8628,40 @@ namespace csv { this->records.clear(); } - CSV_INLINE void CSVStat::calc() { + CSV_INLINE void CSVStat::calc() + { constexpr size_t CALC_CHUNK_SIZE = 5000; - for (auto& row : reader) { + for (auto& row : reader) + { this->records.push_back(std::move(row)); /** Chunk rows */ - if (this->records.size() == CALC_CHUNK_SIZE) { + if (this->records.size() == CALC_CHUNK_SIZE) + { calc_chunk(); } } - if (!this->records.empty()) { - calc_chunk(); + if (!this->records.empty()) + { + calc_chunk(); } } - CSV_INLINE void CSVStat::calc_worker(const size_t &i) { + CSV_INLINE void CSVStat::calc_worker(const size_t& i) + { /** Worker thread for CSVStat::calc() which calculates statistics for one column. - * + * * @param[in] i Column index */ auto current_record = this->records.begin(); - for (size_t processed = 0; current_record != this->records.end(); processed++) { - if (current_record->size() == this->get_col_names().size()) { + for (size_t processed = 0; current_record != this->records.end(); processed++) + { + if (current_record->size() == this->get_col_names().size()) + { auto current_field = (*current_record)[i]; // Optimization: Don't count() if there's too many distinct values in the first 1000 rows @@ -8276,7 +8671,8 @@ namespace csv { this->dtype(current_field, i); // Numeric Stuff - if (current_field.is_num()) { + if (current_field.is_num()) + { long double x_n = current_field.get(); // This actually calculates mean AND variance @@ -8284,7 +8680,8 @@ namespace csv { this->min_max(x_n, i); } } - else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) { + else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) + { throw std::runtime_error("Line has different length than the others " + internals::format_row(*current_record)); } @@ -8292,24 +8689,28 @@ namespace csv { } } - CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t &i) { + CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t& i) + { /** Given a record update the type counter * @param[in] record Data observation * @param[out] i The column index that should be updated */ - + auto type = data.type(); - if (this->dtypes[i].find(type) != - this->dtypes[i].end()) { + if (this->dtypes[i].find(type) != this->dtypes[i].end()) + { // Increment count this->dtypes[i][type]++; - } else { + } + else + { // Initialize count this->dtypes[i].insert(std::make_pair(type, 1)); } } - CSV_INLINE void CSVStat::count(CSVField& data, const size_t &i) { + CSV_INLINE void CSVStat::count(CSVField& data, const size_t& i) + { /** Given a record update the frequency counter * @param[in] record Data observation * @param[out] i The column index that should be updated @@ -8317,17 +8718,20 @@ namespace csv { auto item = data.get(); - if (this->counts[i].find(item) != - this->counts[i].end()) { + if (this->counts[i].find(item) != this->counts[i].end()) + { // Increment count this->counts[i][item]++; - } else { + } + else + { // Initialize count this->counts[i].insert(std::make_pair(item, 1)); } } - CSV_INLINE void CSVStat::min_max(const long double &x_n, const size_t &i) { + CSV_INLINE void CSVStat::min_max(const long double& x_n, const size_t& i) + { /** Update current minimum and maximum * @param[in] x_n Data observation * @param[out] i The column index that should be updated @@ -8336,14 +8740,15 @@ namespace csv { this->mins[i] = x_n; if (std::isnan(this->maxes[i])) this->maxes[i] = x_n; - + if (x_n < this->mins[i]) this->mins[i] = x_n; else if (x_n > this->maxes[i]) this->maxes[i] = x_n; } - CSV_INLINE void CSVStat::variance(const long double &x_n, const size_t &i) { + CSV_INLINE void CSVStat::variance(const long double& x_n, const size_t& i) + { /** Given a record update rolling mean and variance for all columns * using Welford's Algorithm * @param[in] x_n Data observation @@ -8356,14 +8761,17 @@ namespace csv { long double delta2; current_n++; - - if (current_n == 1) { + + if (current_n == 1) + { current_rolling_mean = x_n; - } else { + } + else + { delta = x_n - current_rolling_mean; - current_rolling_mean += delta/current_n; + current_rolling_mean += delta / current_n; delta2 = x_n - current_rolling_mean; - current_rolling_var += delta*delta2; + current_rolling_var += delta * delta2; } } @@ -8375,14 +8783,16 @@ namespace csv { * * \return A mapping of column names to csv::DataType enums */ - CSV_INLINE std::unordered_map csv_data_types(const std::string& filename) { + CSV_INLINE std::unordered_map csv_data_types(const std::string& filename) + { CSVStat stat(filename); std::unordered_map csv_dtypes; auto col_names = stat.get_col_names(); auto temp = stat.get_dtypes(); - for (size_t i = 0; i < stat.get_col_names().size(); i++) { + for (size_t i = 0; i < stat.get_col_names().size(); i++) + { auto& col = temp[i]; auto& col_name = col_names[i]; @@ -8402,12 +8812,12 @@ namespace csv { return csv_dtypes; } -} +} // namespace csv #include #include - -namespace csv { +namespace csv +{ /** Shorthand function for parsing an in-memory CSV string * * @return A collection of CSVRow objects @@ -8415,7 +8825,8 @@ namespace csv { * @par Example * @snippet tests/test_read_csv.cpp Parse Example */ - CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) { + CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) + { std::stringstream stream(in.data()); return CSVReader(stream, format); } @@ -8424,7 +8835,8 @@ namespace csv { * * @return A collection of CSVRow objects */ - CSV_INLINE CSVReader parse_no_header(csv::string_view in) { + CSV_INLINE CSVReader parse_no_header(csv::string_view in) + { CSVFormat format; format.header_row(-1); @@ -8438,12 +8850,14 @@ namespace csv { * @snippet tests/test_read_csv.cpp Escaped Comma * */ - CSV_INLINE CSVReader operator ""_csv(const char* in, size_t n) { + CSV_INLINE CSVReader operator""_csv(const char* in, size_t n) + { return parse(csv::string_view(in, n)); } /** A shorthand for csv::parse_no_header() */ - CSV_INLINE CSVReader operator ""_csv_no_header(const char* in, size_t n) { + CSV_INLINE CSVReader operator""_csv_no_header(const char* in, size_t n) + { return parse_no_header(csv::string_view(in, n)); } @@ -8454,10 +8868,8 @@ namespace csv { * @param[in] col_name Column whose position we should resolve * @param[in] format Format of the CSV file */ - CSV_INLINE int get_col_pos( - csv::string_view filename, - csv::string_view col_name, - const CSVFormat& format) { + CSV_INLINE int get_col_pos(csv::string_view filename, csv::string_view col_name, const CSVFormat& format) + { CSVReader reader(filename, format); return reader.index_of(col_name); } @@ -8465,22 +8877,17 @@ namespace csv { /** Get basic information about a CSV file * @include programs/csv_info.cpp */ - CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) { + CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) + { CSVReader reader(filename); CSVFormat format = reader.get_format(); - for (auto it = reader.begin(); it != reader.end(); ++it); - - CSVFileInfo info = { - filename, - reader.get_col_names(), - format.get_delim(), - reader.n_rows(), - reader.get_col_names().size() - }; + for (auto it = reader.begin(); it != reader.end(); ++it) + ; + + CSVFileInfo info = { filename, reader.get_col_names(), format.get_delim(), reader.n_rows(), reader.get_col_names().size() }; return info; } -} - +} // namespace csv #endif diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 1eb789bd..622fe371 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -11,9 +11,10 @@ #pragma once +#include + #include #include -#include namespace CsvSpawner { diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h index 72a533dd..6ba2fbc1 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerComponent.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp index 55c108e1..6b9fb728 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h index 0e0283c8..8e962dbc 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerCsvParser.h @@ -10,11 +10,7 @@ #pragma once -#include -#include -#include #include -#include #include namespace CsvSpawner::CsvSpawnerUtils diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp index 0aaf1353..d1a0932f 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp @@ -12,7 +12,7 @@ #include "AzCore/Debug/Trace.h" #include "CsvSpawnerComponent.h" #include "CsvSpawnerCsvParser.h" -#include +#include "CsvSpawnerUtils.h" #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h index 0e4b8bee..914cf4a0 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h @@ -10,12 +10,12 @@ #pragma once -#include "API/ToolsApplicationAPI.h" +#include #include +#include #include #include -#include #include #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index d7945534..ca49d91b 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -9,7 +9,7 @@ * file. */ -#include +#include "CsvSpawnerUtils.h" #include #include diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h similarity index 100% rename from Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerUtils.h rename to Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h diff --git a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake index d0f6385b..cd4cc9fe 100644 --- a/Gems/CsvSpawner/Code/csvspawner_api_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_api_files.cmake @@ -2,5 +2,4 @@ set(FILES Include/CsvSpawner/CsvSpawnerInterface.h Include/CsvSpawner/CsvSpawnerTypeIds.h - Include/CsvSpawner/CsvSpawnerUtils.h ) diff --git a/Gems/CsvSpawner/Code/csvspawner_private_files.cmake b/Gems/CsvSpawner/Code/csvspawner_private_files.cmake index a1c05509..b59d4fce 100644 --- a/Gems/CsvSpawner/Code/csvspawner_private_files.cmake +++ b/Gems/CsvSpawner/Code/csvspawner_private_files.cmake @@ -3,6 +3,7 @@ set(FILES Source/CsvSpawnerModuleInterface.cpp Source/CsvSpawnerModuleInterface.h Source/CsvSpawner/CsvSpawnerUtils.cpp + Source/CsvSpawner/CsvSpawnerUtils.h Source/CsvSpawner/CsvSpawnerComponent.cpp Source/CsvSpawner/CsvSpawnerComponent.h ) From 51e19416628b0133b239a75698f9799d32abebad Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:35:16 +0100 Subject: [PATCH 30/47] remove const in func definition Signed-off-by: Wojciech Czerski --- .../Code/Include/CsvSpawner/CsvSpawnerInterface.h | 6 +++--- .../CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 622fe371..eaca5a53 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -30,7 +30,7 @@ namespace CsvSpawner Success = 0, ///< Operation succeeded. Fail = 1 << 0, ///< Generic failure. SpawnStopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. - ErrorOccurred = 1 << 2, ///< An error occurred during spawning (potentially recoverable). + ErrorGenerated = 1 << 2, ///< An error occurred during spawning (potentially recoverable). }; /// Enable bitwise operations for SpawnStatusCode. @@ -64,7 +64,7 @@ namespace CsvSpawner * @brief Called when entity spawning begins. * @param m_spawnInfo Struct holding information about entities to be spawned. */ - virtual void OnEntitiesSpawnBegin(const SpawnInfo& m_spawnInfo) + virtual void OnEntitiesSpawnBegin(SpawnInfo& m_spawnInfo) { } @@ -73,7 +73,7 @@ namespace CsvSpawner * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(const SpawnInfo& m_spawnInfo, const SpawnStatusCode& m_statusCode) + virtual void OnEntitiesSpawnFinished(SpawnInfo& m_spawnInfo, SpawnStatusCode& m_statusCode) { } diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index ca49d91b..5839b7e3 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -233,7 +233,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated; continue; } @@ -264,7 +264,7 @@ namespace CsvSpawner::CsvSpawnerUtils else { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated; continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. @@ -280,7 +280,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated; return; } @@ -297,7 +297,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorOccurred; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated; return; } From 476f2b48b43a0bc36017ffce59a91fbd09c8184c Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:40:48 +0100 Subject: [PATCH 31/47] make interface clas final Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 2 +- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index eaca5a53..e6af4c49 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -55,7 +55,7 @@ namespace CsvSpawner * CsvSpawnerInterface is an Event Bus interface that notifies multiple * listeners when entity spawning begins and finishes. */ - class CsvSpawnerInterface : public AZ::EBusTraits + class CsvSpawnerInterface final : public AZ::EBusTraits { public: virtual ~CsvSpawnerInterface() = default; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 5839b7e3..60beeb9e 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -198,7 +198,7 @@ namespace CsvSpawner::CsvSpawnerUtils { SpawnInfo broadcastSpawnInfo = SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. - SpawnStatusCode spawnStatusCode; // Spawn Status Code Status used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + SpawnStatusCode spawnStatusCode; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. // Call CsvSpawner EBus notification - Begin CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); From 26cb4bd095e8aadc8c3daac2400bdae9f5c9ec66 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:48:04 +0100 Subject: [PATCH 32/47] init value definition | add spawn stop break points Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 60beeb9e..e7bc2e9a 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -198,7 +198,7 @@ namespace CsvSpawner::CsvSpawnerUtils { SpawnInfo broadcastSpawnInfo = SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. - SpawnStatusCode spawnStatusCode; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + SpawnStatusCode spawnStatusCode = SpawnStatusCode::Success; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. // Call CsvSpawner EBus notification - Begin CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); @@ -280,7 +280,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated | SpawnStatusCode::SpawnStopped; return; } @@ -297,7 +297,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated; + spawnStatusCode |= SpawnStatusCode::ErrorGenerated | SpawnStatusCode::SpawnStopped; return; } From 62358ef05ae65407301c40dcf841849536c95420 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:51:35 +0100 Subject: [PATCH 33/47] remove const& from struct definition Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 20 +++++++++---------- .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 12 +++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index e6af4c49..eca98f54 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -22,19 +22,19 @@ namespace CsvSpawner /** * @brief Flags representing the status of an CsvSpawner::Spawn() operation. * - * SpawnStatusCode provides various status indicators for entity spawning. + * SpawnStatus provides various status indicators for entity spawning. * These flags help track whether spawning was successful, stopped, or failed. */ - enum class SpawnStatusCode : uint8_t + enum class SpawnStatus : uint8_t { Success = 0, ///< Operation succeeded. Fail = 1 << 0, ///< Generic failure. - SpawnStopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. - ErrorGenerated = 1 << 2, ///< An error occurred during spawning (potentially recoverable). + Stopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. + Warning = 1 << 2, ///< An warning or error occurred during spawning (potentially recoverable). }; - /// Enable bitwise operations for SpawnStatusCode. - AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatusCode); + /// Enable bitwise operations for SpawnStatus. + AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatus); /** * @brief Structure holding data related to CsvSpawner entity spawning. @@ -44,9 +44,9 @@ namespace CsvSpawner */ struct SpawnInfo { - const AZStd::vector& m_entitiesToSpawn; ///< List of entities to spawn. - const AZStd::string& m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. - const AZ::EntityId& m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. + AZStd::vector m_entitiesToSpawn; ///< List of entities to spawn. + AZStd::string m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. + AZ::EntityId m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. }; /** @@ -73,7 +73,7 @@ namespace CsvSpawner * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(SpawnInfo& m_spawnInfo, SpawnStatusCode& m_statusCode) + virtual void OnEntitiesSpawnFinished(SpawnInfo& m_spawnInfo, SpawnStatus& m_statusCode) { } diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index e7bc2e9a..f66f46ae 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -198,7 +198,7 @@ namespace CsvSpawner::CsvSpawnerUtils { SpawnInfo broadcastSpawnInfo = SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. - SpawnStatusCode spawnStatusCode = SpawnStatusCode::Success; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. // Call CsvSpawner EBus notification - Begin CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); @@ -233,7 +233,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated; + spawnStatusCode |= SpawnStatus::Warning; continue; } @@ -264,7 +264,7 @@ namespace CsvSpawner::CsvSpawnerUtils else { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated; + spawnStatusCode |= SpawnStatus::Warning; continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. @@ -280,7 +280,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated | SpawnStatusCode::SpawnStopped; + spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; return; } @@ -297,7 +297,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatusCode::ErrorGenerated | SpawnStatusCode::SpawnStopped; + spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; return; } @@ -310,7 +310,7 @@ namespace CsvSpawner::CsvSpawnerUtils } // Check is success spawn - tickets.empty() ? spawnStatusCode |= SpawnStatusCode::Fail : spawnStatusCode |= SpawnStatusCode::Success; + tickets.empty() ? spawnStatusCode |= SpawnStatus::Fail : spawnStatusCode |= SpawnStatus::Success; // Call CsvSpawner EBus notification - Finished CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); From 9e3cf1aef63acc9c5449b1f133b829e36db7c91e Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:53:00 +0100 Subject: [PATCH 34/47] remove final from interface Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index eca98f54..8e1ed143 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -55,7 +55,7 @@ namespace CsvSpawner * CsvSpawnerInterface is an Event Bus interface that notifies multiple * listeners when entity spawning begins and finishes. */ - class CsvSpawnerInterface final : public AZ::EBusTraits + class CsvSpawnerInterface : public AZ::EBusTraits { public: virtual ~CsvSpawnerInterface() = default; From 95b70d187fec35a03f7db05ef32f5f08e6d98ed0 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 13:54:10 +0100 Subject: [PATCH 35/47] use constexpr Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 8e1ed143..01565894 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -78,7 +78,7 @@ namespace CsvSpawner } /// EBus Configuration - Allows multiple listeners to handle events. - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; }; // Create an EBus using the notification interface From b30aac21f8ec2288619b7236cfe66736b11b82d2 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 14:24:18 +0100 Subject: [PATCH 36/47] move struct to utils Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 38 ++------------ .../Include/CsvSpawner/CsvSpawnerTypeIds.h | 3 +- .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 50 +++++++++++++++++++ .../Code/Source/CsvSpawner/CsvSpawnerUtils.h | 35 ++++++++++++- 4 files changed, 89 insertions(+), 37 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 01565894..b5d70a66 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -12,43 +12,10 @@ #pragma once #include - #include -#include namespace CsvSpawner { - - /** - * @brief Flags representing the status of an CsvSpawner::Spawn() operation. - * - * SpawnStatus provides various status indicators for entity spawning. - * These flags help track whether spawning was successful, stopped, or failed. - */ - enum class SpawnStatus : uint8_t - { - Success = 0, ///< Operation succeeded. - Fail = 1 << 0, ///< Generic failure. - Stopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. - Warning = 1 << 2, ///< An warning or error occurred during spawning (potentially recoverable). - }; - - /// Enable bitwise operations for SpawnStatus. - AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatus); - - /** - * @brief Structure holding data related to CsvSpawner entity spawning. - * - * SpawnInfo contains information about the entities to be spawned, the physics scene - * they belong to, and the parent entity responsible for the spawn operation. - */ - struct SpawnInfo - { - AZStd::vector m_entitiesToSpawn; ///< List of entities to spawn. - AZStd::string m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. - AZ::EntityId m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. - }; - /** * @brief Interface for handling entity spawn events for Csv Spawner. * @@ -58,13 +25,14 @@ namespace CsvSpawner class CsvSpawnerInterface : public AZ::EBusTraits { public: + AZ_RTTI(CsvSpawnerInterface, CsvSpawnerInterfaceTypeId); virtual ~CsvSpawnerInterface() = default; /** * @brief Called when entity spawning begins. * @param m_spawnInfo Struct holding information about entities to be spawned. */ - virtual void OnEntitiesSpawnBegin(SpawnInfo& m_spawnInfo) + virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) { } @@ -73,7 +41,7 @@ namespace CsvSpawner * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(SpawnInfo& m_spawnInfo, SpawnStatus& m_statusCode) + virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) { } diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h index 328393ec..f067e458 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h @@ -21,5 +21,6 @@ namespace CsvSpawner inline constexpr const char* CsvSpawnerComponentTypeId = "{59b31372-1f3c-4733-b61b-0fe94b5a8f3e}"; // Interface TypeIds - inline constexpr const char* CsvSpawnerRequestsTypeId = "{77ACBD4E-069E-4610-8154-E1AC28CEE05A}"; + inline constexpr const char* CsvSpawnerInterfaceTypeId = "{77ACBD4E-069E-4610-8154-E1AC28CEE05A}"; + inline constexpr const char* CsvSpawnerSpawnInfoTypeId = "{81E5A014-3232-4359-98F5-7F9D7152629E}"; } // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index f66f46ae..aecf271f 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -317,4 +317,54 @@ namespace CsvSpawner::CsvSpawnerUtils return tickets; } + void SpawnInfo::Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + // Reflect SpawnStatus enum + serializeContext->Enum() + ->Version(0) + ->Value("Success", SpawnStatus::Success) + ->Value("Fail", SpawnStatus::Fail) + ->Value("Stopped", SpawnStatus::Stopped) + ->Value("Warning", SpawnStatus::Warning); + + // Reflect SpawnInfo struct + serializeContext->Class() + ->Version(0) + ->Field("EntitiesToSpawn", &SpawnInfo::m_entitiesToSpawn) + ->Field("PhysicsSceneName", &SpawnInfo::m_physicsSceneName) + ->Field("SpawnerParentEntityId", &SpawnInfo::m_spawnerParentEntityId); + + if (auto* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Spawn Info", "Information about entities being spawned") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_entitiesToSpawn, + "Entities to Spawn", + "List of entities to be spawned.") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_physicsSceneName, + "Physics Scene", + "Name of the physics scene where entities will be spawned.") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &SpawnInfo::m_spawnerParentEntityId, + "Parent Entity", + "Parent entity ID responsible for spawning."); + } + } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("SpawnInfo") + ->Constructor() + ->Property("m_entitiesToSpawn", BehaviorValueProperty(&SpawnInfo::m_entitiesToSpawn)) + ->Property("m_physicsSceneName", BehaviorValueProperty(&SpawnInfo::m_physicsSceneName)) + ->Property("m_spawnerParentEntityId", BehaviorValueProperty(&SpawnInfo::m_spawnerParentEntityId)); + } + } } // namespace CsvSpawner::CsvSpawnerUtils diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h index 364c936d..585aecd1 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h @@ -99,4 +99,37 @@ namespace CsvSpawner::CsvSpawnerUtils const AZStd::string& physicsSceneName = AZStd::string(), AZ::EntityId parentId = AZ::EntityId()); -}; // namespace CsvSpawner::CsvSpawnerUtils + /** + * @brief Flags representing the status of an CsvSpawner::Spawn() operation. + * + * SpawnStatus provides various status indicators for entity spawning. + * These flags help track whether spawning was successful, stopped, or failed. + */ + enum class SpawnStatus : uint8_t + { + Success = 0, ///< Operation succeeded. + Fail = 1 << 0, ///< Generic failure. + Stopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. + Warning = 1 << 2, ///< An warning or error occurred during spawning (potentially recoverable). + }; + + /// Enable bitwise operations for SpawnStatus. + AZ_DEFINE_ENUM_BITWISE_OPERATORS(SpawnStatus); + + /** + * @brief Structure holding data related to CsvSpawner entity spawning. + * + * SpawnInfo contains information about the entities to be spawned, the physics scene + * they belong to, and the parent entity responsible for the spawn operation. + */ + struct SpawnInfo + { + AZ_TYPE_INFO(SpawnInfo, CsvSpawnerSpawnInfoTypeId); + static void Reflect(AZ::ReflectContext* context); + + AZStd::vector m_entitiesToSpawn; ///< List of entities to spawn. + AZStd::string m_physicsSceneName; ///< Name of the physics scene where entities will be spawned. + AZ::EntityId m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. + }; + +} // namespace CsvSpawner::CsvSpawnerUtils From 75e373936f959a492679e11f7c44b046f6d8b230 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 14:38:52 +0100 Subject: [PATCH 37/47] add lua / script canvas support Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 24 +++++++++++++++++++ .../Include/CsvSpawner/CsvSpawnerTypeIds.h | 1 + .../CsvSpawner/CsvSpawnerEditorComponent.cpp | 10 ++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index b5d70a66..ccb74d0b 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -12,7 +12,9 @@ #pragma once #include + #include +#include namespace CsvSpawner { @@ -52,4 +54,26 @@ namespace CsvSpawner // Create an EBus using the notification interface using CsvSpawnerNotificationBus = AZ::EBus; + class CsvSpawnerNotificationBusHandler + : public CsvSpawnerNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + public: + AZ_EBUS_BEHAVIOR_BINDER( + CsvSpawnerNotificationBusHandler, + CsvSpawnerNotificationBusHandlerTypeId, + AZ::SystemAllocator, + OnEntitiesSpawnBegin, + OnEntitiesSpawnFinished); + + void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) override + { + Call(FN_OnEntitiesSpawnBegin, m_spawnInfo); + } + + void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) override + { + Call(FN_OnEntitiesSpawnFinished, m_spawnInfo, m_statusCode); + } + }; } // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h index f067e458..43146887 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerTypeIds.h @@ -22,5 +22,6 @@ namespace CsvSpawner // Interface TypeIds inline constexpr const char* CsvSpawnerInterfaceTypeId = "{77ACBD4E-069E-4610-8154-E1AC28CEE05A}"; + inline constexpr const char* CsvSpawnerNotificationBusHandlerTypeId = "{1F142F00-4E79-431B-9C1D-3AB157838FF8}"; inline constexpr const char* CsvSpawnerSpawnInfoTypeId = "{81E5A014-3232-4359-98F5-7F9D7152629E}"; } // namespace CsvSpawner diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp index d1a0932f..050c4583 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp @@ -9,18 +9,18 @@ */ #include "CsvSpawnerEditorComponent.h" -#include "AzCore/Debug/Trace.h" #include "CsvSpawnerComponent.h" #include "CsvSpawnerCsvParser.h" #include "CsvSpawnerUtils.h" +#include #include +#include #include #include #include #include #include -#include namespace CsvSpawner { @@ -63,6 +63,12 @@ namespace CsvSpawner ->Attribute(AZ::Edit::Attributes::ChangeNotify, &CsvSpawnerEditorComponent::OnOnShowLabelsChanged); } } + + if (const auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("CsvSpawnerNotificationBus") + ->Handler(); + } } void CsvSpawnerEditorComponent::OnOnShowLabelsChanged() From 61fc9aaf8923e4d56a451b81f83e507089b34c17 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 15:32:15 +0100 Subject: [PATCH 38/47] add info to readme Signed-off-by: Wojciech Czerski --- readme.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index c597984d..b9c90844 100644 --- a/readme.md +++ b/readme.md @@ -86,6 +86,18 @@ Useful for robots' movement smoothing. Component that spawns prefabs using coordinates stored in CSV file. It supports XYZ format as well as WGS84 coordinate system. ![](doc/CsvSpawner.png) +## API +This Gem has defined notification bus - `CsvSpawnerNotificationBus`. + +Available functions: + +| Name | Parameters | Description | +|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| +| `OnEntitiesSpawnBegin` | `SpawnInfo` - Struct holding information about entities to be spawned | Called when entity spawning begins. | +| `OnEntitiesSpawnFinished` | `SpawnInfo` - Struct holding information about entities to be spawned
`SpawnStatus` - Status code of the spawn (success, warnings, fail). | Called when entity spawning finishes. | + +> *Supports **Lua** and **Script Canvas*** + ## Load object from CSV file CSV file format for coordinates in XYZ system: @@ -98,7 +110,6 @@ x y z name 5.1 65 0 object_name 5.1 72 0 object_name 5.1 79 0 object_name - ``` CSV file format for coordinates in WGS84 system: @@ -111,7 +122,6 @@ alt lat lon name 0 12.5897180240288 30.1932813604207 ball 0 12.5897414039641 30.1933370085065 ball 0 12.5897646831551 30.1933927129084 ball - ``` # ExposeConsoleToRos From 13671a43023187cfddc8d8c59805f9fb3f112612 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 15:55:58 +0100 Subject: [PATCH 39/47] fix headers | make interface func pure virtual Signed-off-by: Wojciech Czerski --- .../Code/Include/CsvSpawner/CsvSpawnerInterface.h | 8 ++------ Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h | 5 ++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index ccb74d0b..f953613c 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -34,18 +34,14 @@ namespace CsvSpawner * @brief Called when entity spawning begins. * @param m_spawnInfo Struct holding information about entities to be spawned. */ - virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) - { - } + virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) = 0; /** * @brief Called when entity spawning finishes. * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) - { - } + virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) = 0; /// EBus Configuration - Allows multiple listeners to handle events. static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h index 585aecd1..1b12ddec 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h @@ -11,14 +11,13 @@ #pragma once -#include "AzFramework/Physics/Collision/CollisionGroups.h" -#include "AzFramework/Physics/Collision/CollisionLayers.h" -#include "CsvSpawner/CsvSpawnerTypeIds.h" +#include #include #include #include #include +#include #include #include From 2c17d4947a74f4a63c4221828482a541c532ee43 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Tue, 18 Mar 2025 16:48:18 +0100 Subject: [PATCH 40/47] fix reflections Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 4 +-- .../CsvSpawner/CsvSpawnerEditorComponent.cpp | 2 ++ .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 33 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index f953613c..8c84faea 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -41,7 +41,7 @@ namespace CsvSpawner * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) = 0; + virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; /// EBus Configuration - Allows multiple listeners to handle events. static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; @@ -67,7 +67,7 @@ namespace CsvSpawner Call(FN_OnEntitiesSpawnBegin, m_spawnInfo); } - void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus& m_statusCode) override + void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) override { Call(FN_OnEntitiesSpawnFinished, m_spawnInfo, m_statusCode); } diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp index 050c4583..192ee24d 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.cpp @@ -27,6 +27,8 @@ namespace CsvSpawner void CsvSpawnerEditorComponent::Reflect(AZ::ReflectContext* context) { + CsvSpawner::SpawnInfo::Reflect(context); + AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index aecf271f..88e79425 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -40,6 +40,32 @@ namespace CsvSpawner::CsvSpawnerUtils ->Field("Transform", &CsvSpawnableEntityInfo::m_transform) ->Field("Name", &CsvSpawnableEntityInfo::m_name) ->Field("Seed", &CsvSpawnableEntityInfo::m_seed); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Csv Spawnable Entity Info", "An entity configuration for spawning") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement(AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_id, "ID", "Optional ID for the entity") + ->DataElement( + AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_transform, "Transform", "Transform of the entity") + ->DataElement( + AZ::Edit::UIHandlers::Default, + &CsvSpawnableEntityInfo::m_name, + "Name", + "Name of the spawnable entity configuration") + ->DataElement( + AZ::Edit::UIHandlers::Default, &CsvSpawnableEntityInfo::m_seed, "Seed", "Optional seed value for randomization"); + } + } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("CsvSpawnableEntityInfo") + ->Constructor<>() + ->Property("Id", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_id)) + ->Property("Transform", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_transform)) + ->Property("Name", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_name)) + ->Property("Seed", BehaviorValueProperty(&CsvSpawnableEntityInfo::m_seed)); } } void CsvSpawnableAssetConfiguration::Reflect(AZ::ReflectContext* context) @@ -360,8 +386,15 @@ namespace CsvSpawner::CsvSpawnerUtils if (auto* behaviorContext = azrtti_cast(context)) { + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Success)>("SpawnStatus_Success"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Fail)>("SpawnStatus_Fail"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Stopped)>("SpawnStatus_Stopped"); + behaviorContext->EnumProperty(CsvSpawnerUtils::SpawnStatus::Warning)>("SpawnStatus_Warning"); + behaviorContext->Class("SpawnInfo") ->Constructor() + ->Attribute(AZ::Script::Attributes::Category, "CsvSpawner") + ->Attribute(AZ::Script::Attributes::Module, "editor") ->Property("m_entitiesToSpawn", BehaviorValueProperty(&SpawnInfo::m_entitiesToSpawn)) ->Property("m_physicsSceneName", BehaviorValueProperty(&SpawnInfo::m_physicsSceneName)) ->Property("m_spawnerParentEntityId", BehaviorValueProperty(&SpawnInfo::m_spawnerParentEntityId)); From 896f067aad29f239ba68eb0672c610778882b8b7 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 12:12:03 +0200 Subject: [PATCH 41/47] revert 3rdParty changes Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp | 8303 ++++++++++----------- 1 file changed, 3948 insertions(+), 4355 deletions(-) diff --git a/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp b/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp index e55f2c24..9cebfc2b 100644 --- a/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp +++ b/Gems/CsvSpawner/Code/3rdParty/csv/csv.hpp @@ -33,15 +33,16 @@ SOFTWARE. * @brief Defines functionality needed for basic CSV parsing */ + #include #include #include #include #include #include +#include #include #include -#include #include /* Copyright 2017 https://github.com/mandreyel @@ -92,591 +93,545 @@ SOFTWARE. #define MIO_PAGE_HEADER #ifdef _WIN32 -#include +# include #else -#include +# include #endif -namespace mio -{ +namespace mio { - /** - * This is used by `basic_mmap` to determine whether to create a read-only or - * a read-write memory mapping. - */ - enum class access_mode - { - read, - write - }; +/** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ +enum class access_mode +{ + read, + write +}; - /** - * Determines the operating system's page allocation granularity. - * - * On the first call to this function, it invokes the operating system specific syscall - * to determine the page size, caches the value, and returns it. Any subsequent call to - * this function serves the cached value, so no further syscalls are made. - */ - inline size_t page_size() +/** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ +inline size_t page_size() +{ + static const size_t page_size = [] { - static const size_t page_size = [] - { #ifdef _WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - return SystemInfo.dwAllocationGranularity; + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; #else - return sysconf(_SC_PAGE_SIZE); + return sysconf(_SC_PAGE_SIZE); #endif - }(); - return page_size; - } + }(); + return page_size; +} - /** - * Alligns `offset` to the operating's system page size such that it subtracts the - * difference until the nearest page boundary before `offset`, or does nothing if - * `offset` is already page aligned. - */ - inline size_t make_offset_page_aligned(size_t offset) noexcept - { - const size_t page_size_ = page_size(); - // Use integer division to round down to the nearest page alignment. - return offset / page_size_ * page_size_; - } +/** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ +inline size_t make_offset_page_aligned(size_t offset) noexcept +{ + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; +} } // namespace mio #endif // MIO_PAGE_HEADER -#include + #include #include #include +#include #ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN -#include +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif // WIN32_LEAN_AND_MEAN +# include #else // ifdef _WIN32 -#define INVALID_HANDLE_VALUE -1 +# define INVALID_HANDLE_VALUE -1 #endif // ifdef _WIN32 -namespace mio -{ +namespace mio { - // This value may be provided as the `length` parameter to the constructor or - // `map`, in which case a memory mapping of the entire file is created. - enum - { - map_entire_file = 0 - }; +// This value may be provided as the `length` parameter to the constructor or +// `map`, in which case a memory mapping of the entire file is created. +enum { map_entire_file = 0 }; #ifdef _WIN32 - using file_handle_type = HANDLE; +using file_handle_type = HANDLE; #else - using file_handle_type = int; +using file_handle_type = int; #endif - // This value represents an invalid file handle type. This can be used to - // determine whether `basic_mmap::file_handle` is valid, for example. - const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; +// This value represents an invalid file handle type. This can be used to +// determine whether `basic_mmap::file_handle` is valid, for example. +const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE; - template - struct basic_mmap - { - using value_type = ByteT; - using size_type = size_t; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using difference_type = std::ptrdiff_t; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using iterator_category = std::random_access_iterator_tag; - using handle_type = file_handle_type; - - static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); - - private: - // Points to the first requested byte, and not to the actual start of the mapping. - pointer data_ = nullptr; - - // Length--in bytes--requested by user (which may not be the length of the - // full mapping) and the length of the full mapping. - size_type length_ = 0; - size_type mapped_length_ = 0; - - // Letting user map a file using both an existing file handle and a path - // introcudes some complexity (see `is_handle_internal_`). - // On POSIX, we only need a file handle to create a mapping, while on - // Windows systems the file handle is necessary to retrieve a file mapping - // handle, but any subsequent operations on the mapped region must be done - // through the latter. - handle_type file_handle_ = INVALID_HANDLE_VALUE; +template +struct basic_mmap +{ + using value_type = ByteT; + using size_type = size_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using difference_type = std::ptrdiff_t; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using iterator_category = std::random_access_iterator_tag; + using handle_type = file_handle_type; + + static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char."); + +private: + // Points to the first requested byte, and not to the actual start of the mapping. + pointer data_ = nullptr; + + // Length--in bytes--requested by user (which may not be the length of the + // full mapping) and the length of the full mapping. + size_type length_ = 0; + size_type mapped_length_ = 0; + + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity (see `is_handle_internal_`). + // On POSIX, we only need a file handle to create a mapping, while on + // Windows systems the file handle is necessary to retrieve a file mapping + // handle, but any subsequent operations on the mapped region must be done + // through the latter. + handle_type file_handle_ = INVALID_HANDLE_VALUE; #ifdef _WIN32 - handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; + handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; #endif - // Letting user map a file using both an existing file handle and a path - // introcudes some complexity in that we must not close the file handle if - // user provided it, but we must close it if we obtained it using the - // provided path. For this reason, this flag is used to determine when to - // close `file_handle_`. - bool is_handle_internal_; + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity in that we must not close the file handle if + // user provided it, but we must close it if we obtained it using the + // provided path. For this reason, this flag is used to determine when to + // close `file_handle_`. + bool is_handle_internal_; - public: - /** - * The default constructed mmap object is in a non-mapped state, that is, - * any operation that attempts to access nonexistent underlying data will - * result in undefined behaviour/segmentation faults. - */ - basic_mmap() = default; +public: + /** + * The default constructed mmap object is in a non-mapped state, that is, + * any operation that attempts to access nonexistent underlying data will + * result in undefined behaviour/segmentation faults. + */ + basic_mmap() = default; #ifdef __cpp_exceptions - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - template - basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(path, offset, length, error); - if (error) - { - throw std::system_error(error); - } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template + basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(path, offset, length, error); + if(error) { throw std::system_error(error); } + } - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(handle, offset, length, error); - if (error) - { - throw std::system_error(error); - } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(handle, offset, length, error); + if(error) { throw std::system_error(error); } + } #endif // __cpp_exceptions - /** - * `basic_mmap` has single-ownership semantics, so transferring ownership - * may only be accomplished by moving the object. - */ - basic_mmap(const basic_mmap&) = delete; - basic_mmap(basic_mmap&&); - basic_mmap& operator=(const basic_mmap&) = delete; - basic_mmap& operator=(basic_mmap&&); - - /** - * If this is a read-write mapping, the destructor invokes sync. Regardless - * of the access mode, unmap is invoked as a final step. - */ - ~basic_mmap(); - - /** - * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, - * however, a mapped region of a file gets its own handle, which is returned by - * 'mapping_handle'. - */ - handle_type file_handle() const noexcept - { - return file_handle_; - } - handle_type mapping_handle() const noexcept; - - /** Returns whether a valid memory mapping has been created. */ - bool is_open() const noexcept - { - return file_handle_ != invalid_handle; - } - - /** - * Returns true if no mapping was established, that is, conceptually the - * same as though the length that was mapped was 0. This function is - * provided so that this class has Container semantics. - */ - bool empty() const noexcept - { - return length() == 0; - } - - /** Returns true if a mapping was established. */ - bool is_mapped() const noexcept; - - /** - * `size` and `length` both return the logical length, i.e. the number of bytes - * user requested to be mapped, while `mapped_length` returns the actual number of - * bytes that were mapped which is a multiple of the underlying operating system's - * page allocation granularity. - */ - size_type size() const noexcept - { - return length(); - } - size_type length() const noexcept - { - return length_; - } - size_type mapped_length() const noexcept - { - return mapped_length_; - } - - /** Returns the offset relative to the start of the mapping. */ - size_type mapping_offset() const noexcept - { - return mapped_length_ - length_; - } - - /** - * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping - * exists. - */ - template::type> - pointer data() noexcept - { - return data_; - } - const_pointer data() const noexcept - { - return data_; - } - - /** - * Returns an iterator to the first requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template::type> - iterator begin() noexcept - { - return data(); - } - const_iterator begin() const noexcept - { - return data(); - } - const_iterator cbegin() const noexcept - { - return data(); - } - - /** - * Returns an iterator one past the last requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template::type> - iterator end() noexcept - { - return data() + length(); - } - const_iterator end() const noexcept - { - return data() + length(); - } - const_iterator cend() const noexcept - { - return data() + length(); - } - - /** - * Returns a reverse iterator to the last memory mapped byte, if a valid - * memory mapping exists, otherwise this function call is undefined - * behaviour. - */ - template::type> - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - const_reverse_iterator rbegin() const noexcept - { - return const_reverse_iterator(end()); - } - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(end()); - } - - /** - * Returns a reverse iterator past the first mapped byte, if a valid memory - * mapping exists, otherwise this function call is undefined behaviour. - */ - template::type> - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - const_reverse_iterator rend() const noexcept - { - return const_reverse_iterator(begin()); - } - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(begin()); - } - - /** - * Returns a reference to the `i`th byte from the first requested byte (as returned - * by `data`). If this is invoked when no valid memory mapping has been created - * prior to this call, undefined behaviour ensues. - */ - reference operator[](const size_type i) noexcept - { - return data_[i]; - } - const_reference operator[](const size_type i) const noexcept - { - return data_[i]; - } - - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - template - void map(const String& path, const size_type offset, const size_type length, std::error_code& error); - - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * The entire file is mapped. - */ - template - void map(const String& path, std::error_code& error) - { - map(path, 0, map_entire_file, error); - } - - /** - * Establishes a memory mapping with AccessMode. If the mapping is - * unsuccesful, the reason is reported via `error` and the object remains in - * a state as if this function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error); - - /** - * Establishes a memory mapping with AccessMode. If the mapping is - * unsuccesful, the reason is reported via `error` and the object remains in - * a state as if this function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * The entire file is mapped. - */ - void map(const handle_type handle, std::error_code& error) - { - map(handle, 0, map_entire_file, error); - } - - /** - * If a valid memory mapping has been created prior to this call, this call - * instructs the kernel to unmap the memory region and disassociate this object - * from the file. - * - * The file handle associated with the file that is mapped is only closed if the - * mapping was created using a file path. If, on the other hand, an existing - * file handle was used to create the mapping, the file handle is not closed. - */ - void unmap(); - - void swap(basic_mmap& other); - - /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ - template - typename std::enable_if
::type sync(std::error_code& error); + /** + * `basic_mmap` has single-ownership semantics, so transferring ownership + * may only be accomplished by moving the object. + */ + basic_mmap(const basic_mmap&) = delete; + basic_mmap(basic_mmap&&); + basic_mmap& operator=(const basic_mmap&) = delete; + basic_mmap& operator=(basic_mmap&&); - /** - * All operators compare the address of the first byte and size of the two mapped - * regions. - */ + /** + * If this is a read-write mapping, the destructor invokes sync. Regardless + * of the access mode, unmap is invoked as a final step. + */ + ~basic_mmap(); - private: - template::type> - pointer get_mapping_start() noexcept - { - return !data() ? nullptr : data() - mapping_offset(); - } + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept { return file_handle_; } + handle_type mapping_handle() const noexcept; - const_pointer get_mapping_start() const noexcept - { - return !data() ? nullptr : data() - mapping_offset(); - } + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept { return file_handle_ != invalid_handle; } - /** - * The destructor syncs changes to disk if `AccessMode` is `write`, but not - * if it's `read`, but since the destructor cannot be templated, we need to - * do SFINAE in a dedicated function, where one syncs and the other is a noop. - */ - template - typename std::enable_if::type conditional_sync(); - template - typename std::enable_if::type conditional_sync(); - }; + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept { return length() == 0; } - template - bool operator==(const basic_mmap& a, const basic_mmap& b); + /** Returns true if a mapping was established. */ + bool is_mapped() const noexcept; - template - bool operator!=(const basic_mmap& a, const basic_mmap& b); + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept { return length(); } + size_type length() const noexcept { return length_; } + size_type mapped_length() const noexcept { return mapped_length_; } - template - bool operator<(const basic_mmap& a, const basic_mmap& b); + /** Returns the offset relative to the start of the mapping. */ + size_type mapping_offset() const noexcept + { + return mapped_length_ - length_; + } - template - bool operator<=(const basic_mmap& a, const basic_mmap& b); + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > pointer data() noexcept { return data_; } + const_pointer data() const noexcept { return data_; } - template - bool operator>(const basic_mmap& a, const basic_mmap& b); + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > iterator begin() noexcept { return data(); } + const_iterator begin() const noexcept { return data(); } + const_iterator cbegin() const noexcept { return data(); } - template - bool operator>=(const basic_mmap& a, const basic_mmap& b); + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > iterator end() noexcept { return data() + length(); } + const_iterator end() const noexcept { return data() + length(); } + const_iterator cend() const noexcept { return data() + length(); } /** - * This is the basis for all read-only mmap objects and should be preferred over - * directly using `basic_mmap`. + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. */ - template - using basic_mmap_source = basic_mmap; + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const noexcept + { return const_reverse_iterator(end()); } /** - * This is the basis for all read-write mmap objects and should be preferred over - * directly using `basic_mmap`. + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. */ - template - using basic_mmap_sink = basic_mmap; + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const noexcept + { return const_reverse_iterator(begin()); } /** - * These aliases cover the most common use cases, both representing a raw byte stream - * (either with a char or an unsigned char/uint8_t). + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. */ - using mmap_source = basic_mmap_source; - using ummap_source = basic_mmap_source; + reference operator[](const size_type i) noexcept { return data_[i]; } + const_reference operator[](const size_type i) const noexcept { return data_[i]; } - using mmap_sink = basic_mmap_sink; - using ummap_sink = basic_mmap_sink; + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template + void map(const String& path, const size_type offset, + const size_type length, std::error_code& error); /** - * Convenience factory method that constructs a mapping for any `basic_mmap` or - * `basic_mmap` type. + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. */ - template - MMap make_mmap(const MappingToken& token, int64_t offset, int64_t length, std::error_code& error) + template + void map(const String& path, std::error_code& error) { - MMap mmap; - mmap.map(token, offset, length, error); - return mmap; + map(path, 0, map_entire_file, error); } /** - * Convenience factory method. + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. * - * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, - * `std::filesystem::path`, `std::vector`, or similar), or a - * `mmap_source::handle_type`. + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. */ - template - mmap_source make_mmap_source( - const MappingToken& token, mmap_source::size_type offset, mmap_source::size_type length, std::error_code& error) - { - return make_mmap(token, offset, length, error); - } + void map(const handle_type handle, const size_type offset, + const size_type length, std::error_code& error); - template - mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) + /** + * Establishes a memory mapping with AccessMode. If the mapping is + * unsuccesful, the reason is reported via `error` and the object remains in + * a state as if this function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code& error) { - return make_mmap_source(token, 0, map_entire_file, error); + map(handle, 0, map_entire_file, error); } /** - * Convenience factory method. + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. * - * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, - * `std::filesystem::path`, `std::vector`, or similar), or a - * `mmap_sink::handle_type`. + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. */ - template - mmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset, mmap_sink::size_type length, std::error_code& error) + void unmap(); + + void swap(basic_mmap& other); + + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template + typename std::enable_if::type + sync(std::error_code& error); + + /** + * All operators compare the address of the first byte and size of the two mapped + * regions. + */ + +private: + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > pointer get_mapping_start() noexcept { - return make_mmap(token, offset, length, error); + return !data() ? nullptr : data() - mapping_offset(); } - template - mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) + const_pointer get_mapping_start() const noexcept { - return make_mmap_sink(token, 0, map_entire_file, error); + return !data() ? nullptr : data() - mapping_offset(); } -} // namespace mio + /** + * The destructor syncs changes to disk if `AccessMode` is `write`, but not + * if it's `read`, but since the destructor cannot be templated, we need to + * do SFINAE in a dedicated function, where one syncs and the other is a noop. + */ + template + typename std::enable_if::type + conditional_sync(); + template + typename std::enable_if::type conditional_sync(); +}; + +template +bool operator==(const basic_mmap& a, + const basic_mmap& b); + +template +bool operator!=(const basic_mmap& a, + const basic_mmap& b); + +template +bool operator<(const basic_mmap& a, + const basic_mmap& b); + +template +bool operator<=(const basic_mmap& a, + const basic_mmap& b); + +template +bool operator>(const basic_mmap& a, + const basic_mmap& b); + +template +bool operator>=(const basic_mmap& a, + const basic_mmap& b); + +/** + * This is the basis for all read-only mmap objects and should be preferred over + * directly using `basic_mmap`. + */ +template +using basic_mmap_source = basic_mmap; -// #include "detail/mmap.ipp" -/* Copyright 2017 https://github.com/mandreyel - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the "Software"), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be included in all copies - * or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/** + * This is the basis for all read-write mmap objects and should be preferred over + * directly using `basic_mmap`. + */ +template +using basic_mmap_sink = basic_mmap; + +/** + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). + */ +using mmap_source = basic_mmap_source; +using ummap_source = basic_mmap_source; + +using mmap_sink = basic_mmap_sink; +using ummap_sink = basic_mmap_sink; + +/** + * Convenience factory method that constructs a mapping for any `basic_mmap` or + * `basic_mmap` type. + */ +template< + typename MMap, + typename MappingToken +> MMap make_mmap(const MappingToken& token, + int64_t offset, int64_t length, std::error_code& error) +{ + MMap mmap; + mmap.map(token, offset, length, error); + return mmap; +} + +/** + * Convenience factory method. + * + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector`, or similar), or a + * `mmap_source::handle_type`. + */ +template +mmap_source make_mmap_source(const MappingToken& token, mmap_source::size_type offset, + mmap_source::size_type length, std::error_code& error) +{ + return make_mmap(token, offset, length, error); +} + +template +mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) +{ + return make_mmap_source(token, 0, map_entire_file, error); +} + +/** + * Convenience factory method. + * + * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`, + * `std::filesystem::path`, `std::vector`, or similar), or a + * `mmap_sink::handle_type`. + */ +template +mmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset, + mmap_sink::size_type length, std::error_code& error) +{ + return make_mmap(token, offset, length, error); +} + +template +mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) +{ + return make_mmap_sink(token, 0, map_entire_file, error); +} + +} // namespace mio + +// #include "detail/mmap.ipp" +/* Copyright 2017 https://github.com/mandreyel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef MIO_BASIC_MMAP_IMPL @@ -712,639 +667,648 @@ namespace mio #include -namespace mio -{ - namespace detail - { +namespace mio { +namespace detail { - template< - typename S, - typename C = typename std::decay::type, - typename = decltype(std::declval().data()), - typename = typename std::enable_if< - std::is_same::value +template< + typename S, + typename C = typename std::decay::type, + typename = decltype(std::declval().data()), + typename = typename std::enable_if< + std::is_same::value #ifdef _WIN32 - || std::is_same::value -#endif - >::type> - struct char_type_helper - { - using type = typename C::value_type; - }; - - template - struct char_type - { - using type = typename char_type_helper::type; - }; - - // TODO: can we avoid this brute force approach? - template<> - struct char_type - { - using type = char; - }; - - template<> - struct char_type - { - using type = char; - }; - - template - struct char_type - { - using type = char; - }; - - template - struct char_type - { - using type = char; - }; + || std::is_same::value +#endif + >::type +> struct char_type_helper { + using type = typename C::value_type; +}; + +template +struct char_type { + using type = typename char_type_helper::type; +}; + +// TODO: can we avoid this brute force approach? +template<> +struct char_type { + using type = char; +}; + +template<> +struct char_type { + using type = char; +}; + +template +struct char_type { + using type = char; +}; + +template +struct char_type { + using type = char; +}; #ifdef _WIN32 - template<> - struct char_type - { - using type = wchar_t; - }; - - template<> - struct char_type - { - using type = wchar_t; - }; - - template - struct char_type - { - using type = wchar_t; - }; - - template - struct char_type - { - using type = wchar_t; - }; +template<> +struct char_type { + using type = wchar_t; +}; + +template<> +struct char_type { + using type = wchar_t; +}; + +template +struct char_type { + using type = wchar_t; +}; + +template +struct char_type { + using type = wchar_t; +}; #endif // _WIN32 - template - struct is_c_str_helper - { - static constexpr bool value = std::is_same< - CharT*, - // TODO: I'm so sorry for this... Can this be made cleaner? - typename std::add_pointer< - typename std::remove_cv::type>::type>::type>::type>::value; - }; - - template - struct is_c_str - { - static constexpr bool value = is_c_str_helper::value; - }; +template +struct is_c_str_helper +{ + static constexpr bool value = std::is_same< + CharT*, + // TODO: I'm so sorry for this... Can this be made cleaner? + typename std::add_pointer< + typename std::remove_cv< + typename std::remove_pointer< + typename std::decay< + S + >::type + >::type + >::type + >::type + >::value; +}; + +template +struct is_c_str +{ + static constexpr bool value = is_c_str_helper::value; +}; #ifdef _WIN32 - template - struct is_c_wstr - { - static constexpr bool value = is_c_str_helper::value; - }; +template +struct is_c_wstr +{ + static constexpr bool value = is_c_str_helper::value; +}; #endif // _WIN32 - template - struct is_c_str_or_c_wstr - { - static constexpr bool value = is_c_str::value +template +struct is_c_str_or_c_wstr +{ + static constexpr bool value = is_c_str::value #ifdef _WIN32 - || is_c_wstr::value + || is_c_wstr::value #endif - ; - }; + ; +}; - template< - typename String, - typename = decltype(std::declval().data()), - typename = typename std::enable_if::value>::type> - const typename char_type::type* c_str(const String& path) - { - return path.data(); - } +template< + typename String, + typename = decltype(std::declval().data()), + typename = typename std::enable_if::value>::type +> const typename char_type::type* c_str(const String& path) +{ + return path.data(); +} - template< - typename String, - typename = decltype(std::declval().empty()), - typename = typename std::enable_if::value>::type> - bool empty(const String& path) - { - return path.empty(); - } +template< + typename String, + typename = decltype(std::declval().empty()), + typename = typename std::enable_if::value>::type +> bool empty(const String& path) +{ + return path.empty(); +} - template::value>::type> - const typename char_type::type* c_str(String path) - { - return path; - } +template< + typename String, + typename = typename std::enable_if::value>::type +> const typename char_type::type* c_str(String path) +{ + return path; +} - template::value>::type> - bool empty(String path) - { - return !path || (*path == 0); - } +template< + typename String, + typename = typename std::enable_if::value>::type +> bool empty(String path) +{ + return !path || (*path == 0); +} - } // namespace detail +} // namespace detail } // namespace mio #endif // MIO_STRING_UTIL_HEADER + #include #ifndef _WIN32 -#include -#include -#include -#include +# include +# include +# include +# include #endif -namespace mio -{ - namespace detail - { +namespace mio { +namespace detail { #ifdef _WIN32 - namespace win - { +namespace win { - /** Returns the 4 upper bytes of an 8-byte integer. */ - inline DWORD int64_high(int64_t n) noexcept - { - return n >> 32; - } +/** Returns the 4 upper bytes of an 8-byte integer. */ +inline DWORD int64_high(int64_t n) noexcept +{ + return n >> 32; +} - /** Returns the 4 lower bytes of an 8-byte integer. */ - inline DWORD int64_low(int64_t n) noexcept - { - return n & 0xffffffff; - } +/** Returns the 4 lower bytes of an 8-byte integer. */ +inline DWORD int64_low(int64_t n) noexcept +{ + return n & 0xffffffff; +} - template::type, char>::value>::type> - file_handle_type open_file_helper(const String& path, const access_mode mode) - { - return ::CreateFileA( - c_str(path), - mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - } +template< + typename String, + typename = typename std::enable_if< + std::is_same::type, char>::value + >::type +> file_handle_type open_file_helper(const String& path, const access_mode mode) +{ + return ::CreateFileA(c_str(path), + mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); +} - template - typename std::enable_if::type, wchar_t>::value, file_handle_type>::type - open_file_helper(const String& path, const access_mode mode) - { - return ::CreateFileW( - c_str(path), - mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - } +template +typename std::enable_if< + std::is_same::type, wchar_t>::value, + file_handle_type +>::type open_file_helper(const String& path, const access_mode mode) +{ + return ::CreateFileW(c_str(path), + mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); +} - } // namespace win +} // win #endif // _WIN32 - /** - * Returns the last platform specific system error (errno on POSIX and - * GetLastError on Win) as a `std::error_code`. - */ - inline std::error_code last_error() noexcept - { - std::error_code error; +/** + * Returns the last platform specific system error (errno on POSIX and + * GetLastError on Win) as a `std::error_code`. + */ +inline std::error_code last_error() noexcept +{ + std::error_code error; #ifdef _WIN32 - error.assign(GetLastError(), std::system_category()); + error.assign(GetLastError(), std::system_category()); #else - error.assign(errno, std::system_category()); + error.assign(errno, std::system_category()); #endif - return error; - } + return error; +} - template - file_handle_type open_file(const String& path, const access_mode mode, std::error_code& error) - { - error.clear(); - if (detail::empty(path)) - { - error = std::make_error_code(std::errc::invalid_argument); - return invalid_handle; - } +template +file_handle_type open_file(const String& path, const access_mode mode, + std::error_code& error) +{ + error.clear(); + if(detail::empty(path)) + { + error = std::make_error_code(std::errc::invalid_argument); + return invalid_handle; + } #ifdef _WIN32 - const auto handle = win::open_file_helper(path, mode); + const auto handle = win::open_file_helper(path, mode); #else // POSIX - const auto handle = ::open(c_str(path), mode == access_mode::read ? O_RDONLY : O_RDWR); + const auto handle = ::open(c_str(path), + mode == access_mode::read ? O_RDONLY : O_RDWR); #endif - if (handle == invalid_handle) - { - error = detail::last_error(); - } - return handle; - } + if(handle == invalid_handle) + { + error = detail::last_error(); + } + return handle; +} - inline size_t query_file_size(file_handle_type handle, std::error_code& error) - { - error.clear(); +inline size_t query_file_size(file_handle_type handle, std::error_code& error) +{ + error.clear(); #ifdef _WIN32 - LARGE_INTEGER file_size; - if (::GetFileSizeEx(handle, &file_size) == 0) - { - error = detail::last_error(); - return 0; - } - return static_cast(file_size.QuadPart); + LARGE_INTEGER file_size; + if(::GetFileSizeEx(handle, &file_size) == 0) + { + error = detail::last_error(); + return 0; + } + return static_cast(file_size.QuadPart); #else // POSIX - struct stat sbuf; - if (::fstat(handle, &sbuf) == -1) - { - error = detail::last_error(); - return 0; - } - return sbuf.st_size; + struct stat sbuf; + if(::fstat(handle, &sbuf) == -1) + { + error = detail::last_error(); + return 0; + } + return sbuf.st_size; #endif - } +} - struct mmap_context - { - char* data; - int64_t length; - int64_t mapped_length; +struct mmap_context +{ + char* data; + int64_t length; + int64_t mapped_length; #ifdef _WIN32 - file_handle_type file_mapping_handle; + file_handle_type file_mapping_handle; #endif - }; +}; - inline mmap_context memory_map( - const file_handle_type file_handle, const int64_t offset, const int64_t length, const access_mode mode, std::error_code& error) - { - const int64_t aligned_offset = make_offset_page_aligned(offset); - const int64_t length_to_map = offset - aligned_offset + length; +inline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset, + const int64_t length, const access_mode mode, std::error_code& error) +{ + const int64_t aligned_offset = make_offset_page_aligned(offset); + const int64_t length_to_map = offset - aligned_offset + length; #ifdef _WIN32 - const int64_t max_file_size = offset + length; - const auto file_mapping_handle = ::CreateFileMapping( - file_handle, - 0, - mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, - win::int64_high(max_file_size), - win::int64_low(max_file_size), - 0); - if (file_mapping_handle == invalid_handle) - { - error = detail::last_error(); - return {}; - } - char* mapping_start = static_cast(::MapViewOfFile( - file_mapping_handle, - mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, - win::int64_high(aligned_offset), - win::int64_low(aligned_offset), - length_to_map)); - if (mapping_start == nullptr) - { - // Close file handle if mapping it failed. - ::CloseHandle(file_mapping_handle); - error = detail::last_error(); - return {}; - } + const int64_t max_file_size = offset + length; + const auto file_mapping_handle = ::CreateFileMapping( + file_handle, + 0, + mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, + win::int64_high(max_file_size), + win::int64_low(max_file_size), + 0); + if(file_mapping_handle == invalid_handle) + { + error = detail::last_error(); + return {}; + } + char* mapping_start = static_cast(::MapViewOfFile( + file_mapping_handle, + mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, + win::int64_high(aligned_offset), + win::int64_low(aligned_offset), + length_to_map)); + if(mapping_start == nullptr) + { + // Close file handle if mapping it failed. + ::CloseHandle(file_mapping_handle); + error = detail::last_error(); + return {}; + } #else // POSIX - char* mapping_start = static_cast(::mmap( - 0, // Don't give hint as to where to map. - length_to_map, - mode == access_mode::read ? PROT_READ : PROT_WRITE, - MAP_SHARED, - file_handle, - aligned_offset)); - if (mapping_start == MAP_FAILED) - { - error = detail::last_error(); - return {}; - } + char* mapping_start = static_cast(::mmap( + 0, // Don't give hint as to where to map. + length_to_map, + mode == access_mode::read ? PROT_READ : PROT_WRITE, + MAP_SHARED, + file_handle, + aligned_offset)); + if(mapping_start == MAP_FAILED) + { + error = detail::last_error(); + return {}; + } #endif - mmap_context ctx; - ctx.data = mapping_start + offset - aligned_offset; - ctx.length = length; - ctx.mapped_length = length_to_map; + mmap_context ctx; + ctx.data = mapping_start + offset - aligned_offset; + ctx.length = length; + ctx.mapped_length = length_to_map; #ifdef _WIN32 - ctx.file_mapping_handle = file_mapping_handle; + ctx.file_mapping_handle = file_mapping_handle; #endif - return ctx; - } + return ctx; +} - } // namespace detail +} // namespace detail - // -- basic_mmap -- +// -- basic_mmap -- - template - basic_mmap::~basic_mmap() - { - conditional_sync(); - unmap(); - } +template +basic_mmap::~basic_mmap() +{ + conditional_sync(); + unmap(); +} - template - basic_mmap::basic_mmap(basic_mmap&& other) - : data_(std::move(other.data_)) - , length_(std::move(other.length_)) - , mapped_length_(std::move(other.mapped_length_)) - , file_handle_(std::move(other.file_handle_)) +template +basic_mmap::basic_mmap(basic_mmap&& other) + : data_(std::move(other.data_)) + , length_(std::move(other.length_)) + , mapped_length_(std::move(other.mapped_length_)) + , file_handle_(std::move(other.file_handle_)) #ifdef _WIN32 - , file_mapping_handle_(std::move(other.file_mapping_handle_)) + , file_mapping_handle_(std::move(other.file_mapping_handle_)) #endif - , is_handle_internal_(std::move(other.is_handle_internal_)) - { - other.data_ = nullptr; - other.length_ = other.mapped_length_ = 0; - other.file_handle_ = invalid_handle; + , is_handle_internal_(std::move(other.is_handle_internal_)) +{ + other.data_ = nullptr; + other.length_ = other.mapped_length_ = 0; + other.file_handle_ = invalid_handle; #ifdef _WIN32 - other.file_mapping_handle_ = invalid_handle; + other.file_mapping_handle_ = invalid_handle; #endif - } +} - template - basic_mmap& basic_mmap::operator=(basic_mmap&& other) +template +basic_mmap& +basic_mmap::operator=(basic_mmap&& other) +{ + if(this != &other) { - if (this != &other) - { - // First the existing mapping needs to be removed. - unmap(); - data_ = std::move(other.data_); - length_ = std::move(other.length_); - mapped_length_ = std::move(other.mapped_length_); - file_handle_ = std::move(other.file_handle_); + // First the existing mapping needs to be removed. + unmap(); + data_ = std::move(other.data_); + length_ = std::move(other.length_); + mapped_length_ = std::move(other.mapped_length_); + file_handle_ = std::move(other.file_handle_); #ifdef _WIN32 - file_mapping_handle_ = std::move(other.file_mapping_handle_); + file_mapping_handle_ = std::move(other.file_mapping_handle_); #endif - is_handle_internal_ = std::move(other.is_handle_internal_); + is_handle_internal_ = std::move(other.is_handle_internal_); - // The moved from basic_mmap's fields need to be reset, because - // otherwise other's destructor will unmap the same mapping that was - // just moved into this. - other.data_ = nullptr; - other.length_ = other.mapped_length_ = 0; - other.file_handle_ = invalid_handle; + // The moved from basic_mmap's fields need to be reset, because + // otherwise other's destructor will unmap the same mapping that was + // just moved into this. + other.data_ = nullptr; + other.length_ = other.mapped_length_ = 0; + other.file_handle_ = invalid_handle; #ifdef _WIN32 - other.file_mapping_handle_ = invalid_handle; + other.file_mapping_handle_ = invalid_handle; #endif - other.is_handle_internal_ = false; - } - return *this; + other.is_handle_internal_ = false; } + return *this; +} - template - typename basic_mmap::handle_type basic_mmap::mapping_handle() const noexcept - { +template +typename basic_mmap::handle_type +basic_mmap::mapping_handle() const noexcept +{ #ifdef _WIN32 - return file_mapping_handle_; + return file_mapping_handle_; #else - return file_handle_; + return file_handle_; #endif - } +} - template - template - void basic_mmap::map(const String& path, const size_type offset, const size_type length, std::error_code& error) +template +template +void basic_mmap::map(const String& path, const size_type offset, + const size_type length, std::error_code& error) +{ + error.clear(); + if(detail::empty(path)) { - error.clear(); - if (detail::empty(path)) - { - error = std::make_error_code(std::errc::invalid_argument); - return; - } - const auto handle = detail::open_file(path, AccessMode, error); - if (error) - { - return; - } + error = std::make_error_code(std::errc::invalid_argument); + return; + } + const auto handle = detail::open_file(path, AccessMode, error); + if(error) + { + return; + } - map(handle, offset, length, error); - // This MUST be after the call to map, as that sets this to true. - if (!error) - { - is_handle_internal_ = true; - } + map(handle, offset, length, error); + // This MUST be after the call to map, as that sets this to true. + if(!error) + { + is_handle_internal_ = true; } +} - template - void basic_mmap::map( - const handle_type handle, const size_type offset, const size_type length, std::error_code& error) +template +void basic_mmap::map(const handle_type handle, + const size_type offset, const size_type length, std::error_code& error) +{ + error.clear(); + if(handle == invalid_handle) { - error.clear(); - if (handle == invalid_handle) - { - error = std::make_error_code(std::errc::bad_file_descriptor); - return; - } + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } - const auto file_size = detail::query_file_size(handle, error); - if (error) - { - return; - } + const auto file_size = detail::query_file_size(handle, error); + if(error) + { + return; + } - if (offset + length > file_size) - { - error = std::make_error_code(std::errc::invalid_argument); - return; - } + if(offset + length > file_size) + { + error = std::make_error_code(std::errc::invalid_argument); + return; + } - const auto ctx = detail::memory_map(handle, offset, length == map_entire_file ? (file_size - offset) : length, AccessMode, error); - if (!error) - { - // We must unmap the previous mapping that may have existed prior to this call. - // Note that this must only be invoked after a new mapping has been created in - // order to provide the strong guarantee that, should the new mapping fail, the - // `map` function leaves this instance in a state as though the function had - // never been invoked. - unmap(); - file_handle_ = handle; - is_handle_internal_ = false; - data_ = reinterpret_cast(ctx.data); - length_ = ctx.length; - mapped_length_ = ctx.mapped_length; + const auto ctx = detail::memory_map(handle, offset, + length == map_entire_file ? (file_size - offset) : length, + AccessMode, error); + if(!error) + { + // We must unmap the previous mapping that may have existed prior to this call. + // Note that this must only be invoked after a new mapping has been created in + // order to provide the strong guarantee that, should the new mapping fail, the + // `map` function leaves this instance in a state as though the function had + // never been invoked. + unmap(); + file_handle_ = handle; + is_handle_internal_ = false; + data_ = reinterpret_cast(ctx.data); + length_ = ctx.length; + mapped_length_ = ctx.mapped_length; #ifdef _WIN32 - file_mapping_handle_ = ctx.file_mapping_handle; + file_mapping_handle_ = ctx.file_mapping_handle; #endif - } } +} - template - template - typename std::enable_if::type basic_mmap::sync(std::error_code& error) +template +template +typename std::enable_if::type +basic_mmap::sync(std::error_code& error) +{ + error.clear(); + if(!is_open()) { - error.clear(); - if (!is_open()) - { - error = std::make_error_code(std::errc::bad_file_descriptor); - return; - } + error = std::make_error_code(std::errc::bad_file_descriptor); + return; + } - if (data()) - { + if(data()) + { #ifdef _WIN32 - if (::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 || ::FlushFileBuffers(file_handle_) == 0) + if(::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 + || ::FlushFileBuffers(file_handle_) == 0) #else // POSIX - if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) + if(::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0) #endif - { - error = detail::last_error(); - return; - } - } -#ifdef _WIN32 - if (::FlushFileBuffers(file_handle_) == 0) { error = detail::last_error(); + return; } -#endif } - - template - void basic_mmap::unmap() +#ifdef _WIN32 + if(::FlushFileBuffers(file_handle_) == 0) { - if (!is_open()) - { - return; - } - // TODO do we care about errors here? + error = detail::last_error(); + } +#endif +} + +template +void basic_mmap::unmap() +{ + if(!is_open()) { return; } + // TODO do we care about errors here? #ifdef _WIN32 - if (is_mapped()) - { - ::UnmapViewOfFile(get_mapping_start()); - ::CloseHandle(file_mapping_handle_); - } + if(is_mapped()) + { + ::UnmapViewOfFile(get_mapping_start()); + ::CloseHandle(file_mapping_handle_); + } #else // POSIX - if (data_) - { - ::munmap(const_cast(get_mapping_start()), mapped_length_); - } + if(data_) { ::munmap(const_cast(get_mapping_start()), mapped_length_); } #endif - // If `file_handle_` was obtained by our opening it (when map is called with - // a path, rather than an existing file handle), we need to close it, - // otherwise it must not be closed as it may still be used outside this - // instance. - if (is_handle_internal_) - { + // If `file_handle_` was obtained by our opening it (when map is called with + // a path, rather than an existing file handle), we need to close it, + // otherwise it must not be closed as it may still be used outside this + // instance. + if(is_handle_internal_) + { #ifdef _WIN32 - ::CloseHandle(file_handle_); + ::CloseHandle(file_handle_); #else // POSIX - ::close(file_handle_); + ::close(file_handle_); #endif - } + } - // Reset fields to their default values. - data_ = nullptr; - length_ = mapped_length_ = 0; - file_handle_ = invalid_handle; + // Reset fields to their default values. + data_ = nullptr; + length_ = mapped_length_ = 0; + file_handle_ = invalid_handle; #ifdef _WIN32 - file_mapping_handle_ = invalid_handle; + file_mapping_handle_ = invalid_handle; #endif - } +} - template - bool basic_mmap::is_mapped() const noexcept - { +template +bool basic_mmap::is_mapped() const noexcept +{ #ifdef _WIN32 - return file_mapping_handle_ != invalid_handle; + return file_mapping_handle_ != invalid_handle; #else // POSIX - return is_open(); + return is_open(); #endif - } +} - template - void basic_mmap::swap(basic_mmap& other) +template +void basic_mmap::swap(basic_mmap& other) +{ + if(this != &other) { - if (this != &other) - { - using std::swap; - swap(data_, other.data_); - swap(file_handle_, other.file_handle_); + using std::swap; + swap(data_, other.data_); + swap(file_handle_, other.file_handle_); #ifdef _WIN32 - swap(file_mapping_handle_, other.file_mapping_handle_); + swap(file_mapping_handle_, other.file_mapping_handle_); #endif - swap(length_, other.length_); - swap(mapped_length_, other.mapped_length_); - swap(is_handle_internal_, other.is_handle_internal_); - } + swap(length_, other.length_); + swap(mapped_length_, other.mapped_length_); + swap(is_handle_internal_, other.is_handle_internal_); } +} - template - template - typename std::enable_if::type basic_mmap::conditional_sync() - { - // This is invoked from the destructor, so not much we can do about - // failures here. - std::error_code ec; - sync(ec); - } +template +template +typename std::enable_if::type +basic_mmap::conditional_sync() +{ + // This is invoked from the destructor, so not much we can do about + // failures here. + std::error_code ec; + sync(ec); +} - template - template - typename std::enable_if::type basic_mmap::conditional_sync() - { - // noop - } +template +template +typename std::enable_if::type +basic_mmap::conditional_sync() +{ + // noop +} - template - bool operator==(const basic_mmap& a, const basic_mmap& b) - { - return a.data() == b.data() && a.size() == b.size(); - } +template +bool operator==(const basic_mmap& a, + const basic_mmap& b) +{ + return a.data() == b.data() + && a.size() == b.size(); +} - template - bool operator!=(const basic_mmap& a, const basic_mmap& b) - { - return !(a == b); - } +template +bool operator!=(const basic_mmap& a, + const basic_mmap& b) +{ + return !(a == b); +} - template - bool operator<(const basic_mmap& a, const basic_mmap& b) - { - if (a.data() == b.data()) - { - return a.size() < b.size(); - } - return a.data() < b.data(); - } +template +bool operator<(const basic_mmap& a, + const basic_mmap& b) +{ + if(a.data() == b.data()) { return a.size() < b.size(); } + return a.data() < b.data(); +} - template - bool operator<=(const basic_mmap& a, const basic_mmap& b) - { - return !(a > b); - } +template +bool operator<=(const basic_mmap& a, + const basic_mmap& b) +{ + return !(a > b); +} - template - bool operator>(const basic_mmap& a, const basic_mmap& b) - { - if (a.data() == b.data()) - { - return a.size() > b.size(); - } - return a.data() > b.data(); - } +template +bool operator>(const basic_mmap& a, + const basic_mmap& b) +{ + if(a.data() == b.data()) { return a.size() > b.size(); } + return a.data() > b.data(); +} - template - bool operator>=(const basic_mmap& a, const basic_mmap& b) - { - return !(a < b); - } +template +bool operator>=(const basic_mmap& a, + const basic_mmap& b) +{ + return !(a < b); +} } // namespace mio #endif // MIO_BASIC_MMAP_IMPL + #endif // MIO_MMAP_HEADER /* Copyright 2017 https://github.com/mandreyel * @@ -1370,57 +1334,56 @@ namespace mio #define MIO_PAGE_HEADER #ifdef _WIN32 -#include +# include #else -#include +# include #endif -namespace mio -{ +namespace mio { - /** - * This is used by `basic_mmap` to determine whether to create a read-only or - * a read-write memory mapping. - */ - enum class access_mode - { - read, - write - }; +/** + * This is used by `basic_mmap` to determine whether to create a read-only or + * a read-write memory mapping. + */ +enum class access_mode +{ + read, + write +}; - /** - * Determines the operating system's page allocation granularity. - * - * On the first call to this function, it invokes the operating system specific syscall - * to determine the page size, caches the value, and returns it. Any subsequent call to - * this function serves the cached value, so no further syscalls are made. - */ - inline size_t page_size() +/** + * Determines the operating system's page allocation granularity. + * + * On the first call to this function, it invokes the operating system specific syscall + * to determine the page size, caches the value, and returns it. Any subsequent call to + * this function serves the cached value, so no further syscalls are made. + */ +inline size_t page_size() +{ + static const size_t page_size = [] { - static const size_t page_size = [] - { #ifdef _WIN32 - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - return SystemInfo.dwAllocationGranularity; + SYSTEM_INFO SystemInfo; + GetSystemInfo(&SystemInfo); + return SystemInfo.dwAllocationGranularity; #else - return sysconf(_SC_PAGE_SIZE); + return sysconf(_SC_PAGE_SIZE); #endif - }(); - return page_size; - } + }(); + return page_size; +} - /** - * Alligns `offset` to the operating's system page size such that it subtracts the - * difference until the nearest page boundary before `offset`, or does nothing if - * `offset` is already page aligned. - */ - inline size_t make_offset_page_aligned(size_t offset) noexcept - { - const size_t page_size_ = page_size(); - // Use integer division to round down to the nearest page alignment. - return offset / page_size_ * page_size_; - } +/** + * Alligns `offset` to the operating's system page size such that it subtracts the + * difference until the nearest page boundary before `offset`, or does nothing if + * `offset` is already page aligned. + */ +inline size_t make_offset_page_aligned(size_t offset) noexcept +{ + const size_t page_size_ = page_size(); + // Use integer division to round down to the nearest page alignment. + return offset / page_size_ * page_size_; +} } // namespace mio @@ -1450,456 +1413,384 @@ namespace mio // #include "mio/mmap.hpp" -#include // std::shared_ptr -#include // std::error_code -namespace mio -{ +#include // std::error_code +#include // std::shared_ptr - /** - * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with - * `std::shared_ptr` semantics. - * - * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if - * shared semantics are not required. - */ - template - class basic_shared_mmap - { - using impl_type = basic_mmap; - std::shared_ptr pimpl_; +namespace mio { - public: - using value_type = typename impl_type::value_type; - using size_type = typename impl_type::size_type; - using reference = typename impl_type::reference; - using const_reference = typename impl_type::const_reference; - using pointer = typename impl_type::pointer; - using const_pointer = typename impl_type::const_pointer; - using difference_type = typename impl_type::difference_type; - using iterator = typename impl_type::iterator; - using const_iterator = typename impl_type::const_iterator; - using reverse_iterator = typename impl_type::reverse_iterator; - using const_reverse_iterator = typename impl_type::const_reverse_iterator; - using iterator_category = typename impl_type::iterator_category; - using handle_type = typename impl_type::handle_type; - using mmap_type = impl_type; - - basic_shared_mmap() = default; - basic_shared_mmap(const basic_shared_mmap&) = default; - basic_shared_mmap& operator=(const basic_shared_mmap&) = default; - basic_shared_mmap(basic_shared_mmap&&) = default; - basic_shared_mmap& operator=(basic_shared_mmap&&) = default; - - /** Takes ownership of an existing mmap object. */ - basic_shared_mmap(mmap_type&& mmap) - : pimpl_(std::make_shared(std::move(mmap))) - { - } - - /** Takes ownership of an existing mmap object. */ - basic_shared_mmap& operator=(mmap_type&& mmap) - { - pimpl_ = std::make_shared(std::move(mmap)); - return *this; - } +/** + * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with + * `std::shared_ptr` semantics. + * + * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if + * shared semantics are not required. + */ +template< + access_mode AccessMode, + typename ByteT +> class basic_shared_mmap +{ + using impl_type = basic_mmap; + std::shared_ptr pimpl_; + +public: + using value_type = typename impl_type::value_type; + using size_type = typename impl_type::size_type; + using reference = typename impl_type::reference; + using const_reference = typename impl_type::const_reference; + using pointer = typename impl_type::pointer; + using const_pointer = typename impl_type::const_pointer; + using difference_type = typename impl_type::difference_type; + using iterator = typename impl_type::iterator; + using const_iterator = typename impl_type::const_iterator; + using reverse_iterator = typename impl_type::reverse_iterator; + using const_reverse_iterator = typename impl_type::const_reverse_iterator; + using iterator_category = typename impl_type::iterator_category; + using handle_type = typename impl_type::handle_type; + using mmap_type = impl_type; + + basic_shared_mmap() = default; + basic_shared_mmap(const basic_shared_mmap&) = default; + basic_shared_mmap& operator=(const basic_shared_mmap&) = default; + basic_shared_mmap(basic_shared_mmap&&) = default; + basic_shared_mmap& operator=(basic_shared_mmap&&) = default; + + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap(mmap_type&& mmap) + : pimpl_(std::make_shared(std::move(mmap))) + {} + + /** Takes ownership of an existing mmap object. */ + basic_shared_mmap& operator=(mmap_type&& mmap) + { + pimpl_ = std::make_shared(std::move(mmap)); + return *this; + } - /** Initializes this object with an already established shared mmap. */ - basic_shared_mmap(std::shared_ptr mmap) - : pimpl_(std::move(mmap)) - { - } + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap(std::shared_ptr mmap) : pimpl_(std::move(mmap)) {} - /** Initializes this object with an already established shared mmap. */ - basic_shared_mmap& operator=(std::shared_ptr mmap) - { - pimpl_ = std::move(mmap); - return *this; - } + /** Initializes this object with an already established shared mmap. */ + basic_shared_mmap& operator=(std::shared_ptr mmap) + { + pimpl_ = std::move(mmap); + return *this; + } #ifdef __cpp_exceptions - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - template - basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(path, offset, length, error); - if (error) - { - throw std::system_error(error); - } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + template + basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(path, offset, length, error); + if(error) { throw std::system_error(error); } + } - /** - * The same as invoking the `map` function, except any error that may occur - * while establishing the mapping is wrapped in a `std::system_error` and is - * thrown. - */ - basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) - { - std::error_code error; - map(handle, offset, length, error); - if (error) - { - throw std::system_error(error); - } - } + /** + * The same as invoking the `map` function, except any error that may occur + * while establishing the mapping is wrapped in a `std::system_error` and is + * thrown. + */ + basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) + { + std::error_code error; + map(handle, offset, length, error); + if(error) { throw std::system_error(error); } + } #endif // __cpp_exceptions - /** - * If this is a read-write mapping and the last reference to the mapping, - * the destructor invokes sync. Regardless of the access mode, unmap is - * invoked as a final step. - */ - ~basic_shared_mmap() = default; + /** + * If this is a read-write mapping and the last reference to the mapping, + * the destructor invokes sync. Regardless of the access mode, unmap is + * invoked as a final step. + */ + ~basic_shared_mmap() = default; - /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ - std::shared_ptr get_shared_ptr() - { - return pimpl_; - } + /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */ + std::shared_ptr get_shared_ptr() { return pimpl_; } - /** - * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, - * however, a mapped region of a file gets its own handle, which is returned by - * 'mapping_handle'. - */ - handle_type file_handle() const noexcept - { - return pimpl_ ? pimpl_->file_handle() : invalid_handle; - } + /** + * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows, + * however, a mapped region of a file gets its own handle, which is returned by + * 'mapping_handle'. + */ + handle_type file_handle() const noexcept + { + return pimpl_ ? pimpl_->file_handle() : invalid_handle; + } - handle_type mapping_handle() const noexcept - { - return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; - } + handle_type mapping_handle() const noexcept + { + return pimpl_ ? pimpl_->mapping_handle() : invalid_handle; + } - /** Returns whether a valid memory mapping has been created. */ - bool is_open() const noexcept - { - return pimpl_ && pimpl_->is_open(); - } + /** Returns whether a valid memory mapping has been created. */ + bool is_open() const noexcept { return pimpl_ && pimpl_->is_open(); } - /** - * Returns true if no mapping was established, that is, conceptually the - * same as though the length that was mapped was 0. This function is - * provided so that this class has Container semantics. - */ - bool empty() const noexcept - { - return !pimpl_ || pimpl_->empty(); - } + /** + * Returns true if no mapping was established, that is, conceptually the + * same as though the length that was mapped was 0. This function is + * provided so that this class has Container semantics. + */ + bool empty() const noexcept { return !pimpl_ || pimpl_->empty(); } - /** - * `size` and `length` both return the logical length, i.e. the number of bytes - * user requested to be mapped, while `mapped_length` returns the actual number of - * bytes that were mapped which is a multiple of the underlying operating system's - * page allocation granularity. - */ - size_type size() const noexcept - { - return pimpl_ ? pimpl_->length() : 0; - } - size_type length() const noexcept - { - return pimpl_ ? pimpl_->length() : 0; - } - size_type mapped_length() const noexcept - { - return pimpl_ ? pimpl_->mapped_length() : 0; - } + /** + * `size` and `length` both return the logical length, i.e. the number of bytes + * user requested to be mapped, while `mapped_length` returns the actual number of + * bytes that were mapped which is a multiple of the underlying operating system's + * page allocation granularity. + */ + size_type size() const noexcept { return pimpl_ ? pimpl_->length() : 0; } + size_type length() const noexcept { return pimpl_ ? pimpl_->length() : 0; } + size_type mapped_length() const noexcept + { + return pimpl_ ? pimpl_->mapped_length() : 0; + } - /** - * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping - * exists. - */ - template::type> - pointer data() noexcept - { - return pimpl_->data(); - } - const_pointer data() const noexcept - { - return pimpl_ ? pimpl_->data() : nullptr; - } + /** + * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping + * exists. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > pointer data() noexcept { return pimpl_->data(); } + const_pointer data() const noexcept { return pimpl_ ? pimpl_->data() : nullptr; } - /** - * Returns an iterator to the first requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - iterator begin() noexcept - { - return pimpl_->begin(); - } - const_iterator begin() const noexcept - { - return pimpl_->begin(); - } - const_iterator cbegin() const noexcept - { - return pimpl_->cbegin(); - } + /** + * Returns an iterator to the first requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + iterator begin() noexcept { return pimpl_->begin(); } + const_iterator begin() const noexcept { return pimpl_->begin(); } + const_iterator cbegin() const noexcept { return pimpl_->cbegin(); } - /** - * Returns an iterator one past the last requested byte, if a valid memory mapping - * exists, otherwise this function call is undefined behaviour. - */ - template::type> - iterator end() noexcept - { - return pimpl_->end(); - } - const_iterator end() const noexcept - { - return pimpl_->end(); - } - const_iterator cend() const noexcept - { - return pimpl_->cend(); - } + /** + * Returns an iterator one past the last requested byte, if a valid memory mapping + * exists, otherwise this function call is undefined behaviour. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > iterator end() noexcept { return pimpl_->end(); } + const_iterator end() const noexcept { return pimpl_->end(); } + const_iterator cend() const noexcept { return pimpl_->cend(); } - /** - * Returns a reverse iterator to the last memory mapped byte, if a valid - * memory mapping exists, otherwise this function call is undefined - * behaviour. - */ - template::type> - reverse_iterator rbegin() noexcept - { - return pimpl_->rbegin(); - } - const_reverse_iterator rbegin() const noexcept - { - return pimpl_->rbegin(); - } - const_reverse_iterator crbegin() const noexcept - { - return pimpl_->crbegin(); - } + /** + * Returns a reverse iterator to the last memory mapped byte, if a valid + * memory mapping exists, otherwise this function call is undefined + * behaviour. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > reverse_iterator rbegin() noexcept { return pimpl_->rbegin(); } + const_reverse_iterator rbegin() const noexcept { return pimpl_->rbegin(); } + const_reverse_iterator crbegin() const noexcept { return pimpl_->crbegin(); } - /** - * Returns a reverse iterator past the first mapped byte, if a valid memory - * mapping exists, otherwise this function call is undefined behaviour. - */ - template::type> - reverse_iterator rend() noexcept - { - return pimpl_->rend(); - } - const_reverse_iterator rend() const noexcept - { - return pimpl_->rend(); - } - const_reverse_iterator crend() const noexcept - { - return pimpl_->crend(); - } + /** + * Returns a reverse iterator past the first mapped byte, if a valid memory + * mapping exists, otherwise this function call is undefined behaviour. + */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > reverse_iterator rend() noexcept { return pimpl_->rend(); } + const_reverse_iterator rend() const noexcept { return pimpl_->rend(); } + const_reverse_iterator crend() const noexcept { return pimpl_->crend(); } - /** - * Returns a reference to the `i`th byte from the first requested byte (as returned - * by `data`). If this is invoked when no valid memory mapping has been created - * prior to this call, undefined behaviour ensues. - */ - reference operator[](const size_type i) noexcept - { - return (*pimpl_)[i]; - } - const_reference operator[](const size_type i) const noexcept - { - return (*pimpl_)[i]; - } + /** + * Returns a reference to the `i`th byte from the first requested byte (as returned + * by `data`). If this is invoked when no valid memory mapping has been created + * prior to this call, undefined behaviour ensues. + */ + reference operator[](const size_type i) noexcept { return (*pimpl_)[i]; } + const_reference operator[](const size_type i) const noexcept { return (*pimpl_)[i]; } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - template - void map(const String& path, const size_type offset, const size_type length, std::error_code& error) - { - map_impl(path, offset, length, error); - } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + template + void map(const String& path, const size_type offset, + const size_type length, std::error_code& error) + { + map_impl(path, offset, length, error); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `path`, which must be a path to an existing file, is used to retrieve a file - * handle (which is closed when the object destructs or `unmap` is called), which is - * then used to memory map the requested region. Upon failure, `error` is set to - * indicate the reason and the object remains in an unmapped state. - * - * The entire file is mapped. - */ - template - void map(const String& path, std::error_code& error) - { - map_impl(path, 0, map_entire_file, error); - } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `path`, which must be a path to an existing file, is used to retrieve a file + * handle (which is closed when the object destructs or `unmap` is called), which is + * then used to memory map the requested region. Upon failure, `error` is set to + * indicate the reason and the object remains in an unmapped state. + * + * The entire file is mapped. + */ + template + void map(const String& path, std::error_code& error) + { + map_impl(path, 0, map_entire_file, error); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * `offset` is the number of bytes, relative to the start of the file, where the - * mapping should begin. When specifying it, there is no need to worry about - * providing a value that is aligned with the operating system's page allocation - * granularity. This is adjusted by the implementation such that the first requested - * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at - * `offset` from the start of the file. - * - * `length` is the number of bytes to map. It may be `map_entire_file`, in which - * case a mapping of the entire file is created. - */ - void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error) - { - map_impl(handle, offset, length, error); - } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * `offset` is the number of bytes, relative to the start of the file, where the + * mapping should begin. When specifying it, there is no need to worry about + * providing a value that is aligned with the operating system's page allocation + * granularity. This is adjusted by the implementation such that the first requested + * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at + * `offset` from the start of the file. + * + * `length` is the number of bytes to map. It may be `map_entire_file`, in which + * case a mapping of the entire file is created. + */ + void map(const handle_type handle, const size_type offset, + const size_type length, std::error_code& error) + { + map_impl(handle, offset, length, error); + } - /** - * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the - * reason is reported via `error` and the object remains in a state as if this - * function hadn't been called. - * - * `handle`, which must be a valid file handle, which is used to memory map the - * requested region. Upon failure, `error` is set to indicate the reason and the - * object remains in an unmapped state. - * - * The entire file is mapped. - */ - void map(const handle_type handle, std::error_code& error) - { - map_impl(handle, 0, map_entire_file, error); - } + /** + * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the + * reason is reported via `error` and the object remains in a state as if this + * function hadn't been called. + * + * `handle`, which must be a valid file handle, which is used to memory map the + * requested region. Upon failure, `error` is set to indicate the reason and the + * object remains in an unmapped state. + * + * The entire file is mapped. + */ + void map(const handle_type handle, std::error_code& error) + { + map_impl(handle, 0, map_entire_file, error); + } - /** - * If a valid memory mapping has been created prior to this call, this call - * instructs the kernel to unmap the memory region and disassociate this object - * from the file. - * - * The file handle associated with the file that is mapped is only closed if the - * mapping was created using a file path. If, on the other hand, an existing - * file handle was used to create the mapping, the file handle is not closed. - */ - void unmap() - { - if (pimpl_) - pimpl_->unmap(); - } + /** + * If a valid memory mapping has been created prior to this call, this call + * instructs the kernel to unmap the memory region and disassociate this object + * from the file. + * + * The file handle associated with the file that is mapped is only closed if the + * mapping was created using a file path. If, on the other hand, an existing + * file handle was used to create the mapping, the file handle is not closed. + */ + void unmap() { if(pimpl_) pimpl_->unmap(); } - void swap(basic_shared_mmap& other) - { - pimpl_.swap(other.pimpl_); - } + void swap(basic_shared_mmap& other) { pimpl_.swap(other.pimpl_); } - /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ - template::type> - void sync(std::error_code& error) - { - if (pimpl_) - pimpl_->sync(error); - } + /** Flushes the memory mapped page to disk. Errors are reported via `error`. */ + template< + access_mode A = AccessMode, + typename = typename std::enable_if::type + > void sync(std::error_code& error) { if(pimpl_) pimpl_->sync(error); } - /** All operators compare the underlying `basic_mmap`'s addresses. */ + /** All operators compare the underlying `basic_mmap`'s addresses. */ - friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ == b.pimpl_; - } + friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ == b.pimpl_; + } - friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return !(a == b); - } + friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return !(a == b); + } - friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ < b.pimpl_; - } + friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ < b.pimpl_; + } - friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ <= b.pimpl_; - } + friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ <= b.pimpl_; + } - friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) - { - return a.pimpl_ > b.pimpl_; - } + friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ > b.pimpl_; + } + + friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) + { + return a.pimpl_ >= b.pimpl_; + } - friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) +private: + template + void map_impl(const MappingToken& token, const size_type offset, + const size_type length, std::error_code& error) + { + if(!pimpl_) { - return a.pimpl_ >= b.pimpl_; + mmap_type mmap = make_mmap(token, offset, length, error); + if(error) { return; } + pimpl_ = std::make_shared(std::move(mmap)); } - - private: - template - void map_impl(const MappingToken& token, const size_type offset, const size_type length, std::error_code& error) + else { - if (!pimpl_) - { - mmap_type mmap = make_mmap(token, offset, length, error); - if (error) - { - return; - } - pimpl_ = std::make_shared(std::move(mmap)); - } - else - { - pimpl_->map(token, offset, length, error); - } + pimpl_->map(token, offset, length, error); } - }; + } +}; - /** - * This is the basis for all read-only mmap objects and should be preferred over - * directly using basic_shared_mmap. - */ - template - using basic_shared_mmap_source = basic_shared_mmap; +/** + * This is the basis for all read-only mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ +template +using basic_shared_mmap_source = basic_shared_mmap; - /** - * This is the basis for all read-write mmap objects and should be preferred over - * directly using basic_shared_mmap. - */ - template - using basic_shared_mmap_sink = basic_shared_mmap; +/** + * This is the basis for all read-write mmap objects and should be preferred over + * directly using basic_shared_mmap. + */ +template +using basic_shared_mmap_sink = basic_shared_mmap; - /** - * These aliases cover the most common use cases, both representing a raw byte stream - * (either with a char or an unsigned char/uint8_t). - */ - using shared_mmap_source = basic_shared_mmap_source; - using shared_ummap_source = basic_shared_mmap_source; +/** + * These aliases cover the most common use cases, both representing a raw byte stream + * (either with a char or an unsigned char/uint8_t). + */ +using shared_mmap_source = basic_shared_mmap_source; +using shared_ummap_source = basic_shared_mmap_source; - using shared_mmap_sink = basic_shared_mmap_sink; - using shared_ummap_sink = basic_shared_mmap_sink; +using shared_mmap_sink = basic_shared_mmap_sink; +using shared_ummap_sink = basic_shared_mmap_sink; } // namespace mio @@ -1916,14 +1807,14 @@ namespace mio #include #include #include -#include #include #include +#include #include #include -#include #include +#include #include /** @file @@ -1937,19 +1828,19 @@ namespace mio #include #if defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#undef max -#undef min +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# undef max +# undef min #elif defined(__linux__) -#include +# include #endif -/** Helper macro which should be #defined as "inline" - * in the single header version - */ + /** Helper macro which should be #defined as "inline" + * in the single header version + */ #define CSV_INLINE inline #include @@ -1962,100 +1853,98 @@ namespace mio // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + #ifndef NONSTD_SV_LITE_H_INCLUDED #define NONSTD_SV_LITE_H_INCLUDED -#define string_view_lite_MAJOR 1 -#define string_view_lite_MINOR 1 -#define string_view_lite_PATCH 0 +#define string_view_lite_MAJOR 1 +#define string_view_lite_MINOR 1 +#define string_view_lite_PATCH 0 -#define string_view_lite_VERSION \ - nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH) +#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH) -#define nssv_STRINGIFY(x) nssv_STRINGIFY_(x) -#define nssv_STRINGIFY_(x) #x +#define nssv_STRINGIFY( x ) nssv_STRINGIFY_( x ) +#define nssv_STRINGIFY_( x ) #x // string-view lite configuration: -#define nssv_STRING_VIEW_DEFAULT 0 -#define nssv_STRING_VIEW_NONSTD 1 -#define nssv_STRING_VIEW_STD 2 +#define nssv_STRING_VIEW_DEFAULT 0 +#define nssv_STRING_VIEW_NONSTD 1 +#define nssv_STRING_VIEW_STD 2 -#if !defined(nssv_CONFIG_SELECT_STRING_VIEW) -#define nssv_CONFIG_SELECT_STRING_VIEW (nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD) +#if !defined( nssv_CONFIG_SELECT_STRING_VIEW ) +# define nssv_CONFIG_SELECT_STRING_VIEW ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD ) #endif -#if defined(nssv_CONFIG_SELECT_STD_STRING_VIEW) || defined(nssv_CONFIG_SELECT_NONSTD_STRING_VIEW) -#error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_... +#if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW ) +# error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_... #endif -#ifndef nssv_CONFIG_STD_SV_OPERATOR -#define nssv_CONFIG_STD_SV_OPERATOR 0 +#ifndef nssv_CONFIG_STD_SV_OPERATOR +# define nssv_CONFIG_STD_SV_OPERATOR 0 #endif -#ifndef nssv_CONFIG_USR_SV_OPERATOR -#define nssv_CONFIG_USR_SV_OPERATOR 1 +#ifndef nssv_CONFIG_USR_SV_OPERATOR +# define nssv_CONFIG_USR_SV_OPERATOR 1 #endif -#ifdef nssv_CONFIG_CONVERSION_STD_STRING -#define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING -#define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING +#ifdef nssv_CONFIG_CONVERSION_STD_STRING +# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS nssv_CONFIG_CONVERSION_STD_STRING +# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS nssv_CONFIG_CONVERSION_STD_STRING #endif -#ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS -#define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1 +#ifndef nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS +# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS 1 #endif -#ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -#define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1 +#ifndef nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS +# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS 1 #endif // Control presence of exception handling (try and auto discover): #ifndef nssv_CONFIG_NO_EXCEPTIONS -#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) -#define nssv_CONFIG_NO_EXCEPTIONS 0 -#else -#define nssv_CONFIG_NO_EXCEPTIONS 1 -#endif +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define nssv_CONFIG_NO_EXCEPTIONS 0 +# else +# define nssv_CONFIG_NO_EXCEPTIONS 1 +# endif #endif // C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. -#ifndef nssv_CPLUSPLUS -#if defined(_MSVC_LANG) && !defined(__clang__) -#define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) -#else -#define nssv_CPLUSPLUS __cplusplus -#endif +#ifndef nssv_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define nssv_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define nssv_CPLUSPLUS __cplusplus +# endif #endif -#define nssv_CPP98_OR_GREATER (nssv_CPLUSPLUS >= 199711L) -#define nssv_CPP11_OR_GREATER (nssv_CPLUSPLUS >= 201103L) -#define nssv_CPP11_OR_GREATER_ (nssv_CPLUSPLUS >= 201103L) -#define nssv_CPP14_OR_GREATER (nssv_CPLUSPLUS >= 201402L) -#define nssv_CPP17_OR_GREATER (nssv_CPLUSPLUS >= 201703L) -#define nssv_CPP20_OR_GREATER (nssv_CPLUSPLUS >= 202000L) +#define nssv_CPP98_OR_GREATER ( nssv_CPLUSPLUS >= 199711L ) +#define nssv_CPP11_OR_GREATER ( nssv_CPLUSPLUS >= 201103L ) +#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L ) +#define nssv_CPP14_OR_GREATER ( nssv_CPLUSPLUS >= 201402L ) +#define nssv_CPP17_OR_GREATER ( nssv_CPLUSPLUS >= 201703L ) +#define nssv_CPP20_OR_GREATER ( nssv_CPLUSPLUS >= 202000L ) // use C++17 std::string_view if available and requested: -#if nssv_CPP17_OR_GREATER && defined(__has_include) -#if __has_include( ) -#define nssv_HAVE_STD_STRING_VIEW 1 -#else -#define nssv_HAVE_STD_STRING_VIEW 0 -#endif +#if nssv_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define nssv_HAVE_STD_STRING_VIEW 1 +# else +# define nssv_HAVE_STD_STRING_VIEW 0 +# endif #else -#define nssv_HAVE_STD_STRING_VIEW 0 +# define nssv_HAVE_STD_STRING_VIEW 0 #endif -#define nssv_USES_STD_STRING_VIEW \ - ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || \ - ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW)) +#define nssv_USES_STD_STRING_VIEW ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) ) -#define nssv_HAVE_STARTS_WITH (nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW) -#define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH +#define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW ) +#define nssv_HAVE_ENDS_WITH nssv_HAVE_STARTS_WITH // // Use C++17 std::string_view: @@ -2069,58 +1958,57 @@ namespace mio #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd -{ +namespace nonstd { - template> - std::basic_string to_string(std::basic_string_view v, Allocator const& a = Allocator()) - { - return std::basic_string(v.begin(), v.end(), a); - } +template< class CharT, class Traits, class Allocator = std::allocator > +std::basic_string +to_string( std::basic_string_view v, Allocator const & a = Allocator() ) +{ + return std::basic_string( v.begin(), v.end(), a ); +} - template - std::basic_string_view to_string_view(std::basic_string const& s) - { - return std::basic_string_view(s.data(), s.size()); - } +template< class CharT, class Traits, class Allocator > +std::basic_string_view +to_string_view( std::basic_string const & s ) +{ + return std::basic_string_view( s.data(), s.size() ); +} - // Literal operators sv and _sv: +// Literal operators sv and _sv: #if nssv_CONFIG_STD_SV_OPERATOR - using namespace std::literals::string_view_literals; +using namespace std::literals::string_view_literals; #endif #if nssv_CONFIG_USR_SV_OPERATOR - inline namespace literals - { - inline namespace string_view_literals - { +inline namespace literals { +inline namespace string_view_literals { - constexpr std::string_view operator"" _sv(const char* str, size_t len) noexcept // (1) - { - return std::string_view{ str, len }; - } - constexpr std::u16string_view operator"" _sv(const char16_t* str, size_t len) noexcept // (2) - { - return std::u16string_view{ str, len }; - } +constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1) +{ + return std::string_view{ str, len }; +} - constexpr std::u32string_view operator"" _sv(const char32_t* str, size_t len) noexcept // (3) - { - return std::u32string_view{ str, len }; - } +constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2) +{ + return std::u16string_view{ str, len }; +} - constexpr std::wstring_view operator"" _sv(const wchar_t* str, size_t len) noexcept // (4) - { - return std::wstring_view{ str, len }; - } +constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3) +{ + return std::u32string_view{ str, len }; +} - } // namespace string_view_literals - } // namespace literals +constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4) +{ + return std::wstring_view{ str, len }; +} + +}} // namespace literals::string_view_literals #endif // nssv_CONFIG_USR_SV_OPERATOR @@ -2128,25 +2016,24 @@ namespace nonstd #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd -{ +namespace nonstd { - using std::basic_string_view; - using std::string_view; - using std::u16string_view; - using std::u32string_view; - using std::wstring_view; +using std::string_view; +using std::wstring_view; +using std::u16string_view; +using std::u32string_view; +using std::basic_string_view; - // literal "sv" and "_sv", see above +// literal "sv" and "_sv", see above - using std::operator==; - using std::operator!=; - using std::operator<; - using std::operator<=; - using std::operator>; - using std::operator>=; +using std::operator==; +using std::operator!=; +using std::operator<; +using std::operator<=; +using std::operator>; +using std::operator>=; - using std::operator<<; +using std::operator<<; } // namespace nonstd @@ -2169,115 +2056,115 @@ namespace nonstd // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) -#if defined(_MSC_VER) && !defined(__clang__) -#define nssv_COMPILER_MSVC_VER (_MSC_VER) -#define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) +#if defined(_MSC_VER ) && !defined(__clang__) +# define nssv_COMPILER_MSVC_VER (_MSC_VER ) +# define nssv_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) #else -#define nssv_COMPILER_MSVC_VER 0 -#define nssv_COMPILER_MSVC_VERSION 0 +# define nssv_COMPILER_MSVC_VER 0 +# define nssv_COMPILER_MSVC_VERSION 0 #endif -#define nssv_COMPILER_VERSION(major, minor, patch) (10 * (10 * major + minor) + patch) +#define nssv_COMPILER_VERSION( major, minor, patch ) (10 * ( 10 * major + minor) + patch) #if defined(__clang__) -#define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else -#define nssv_COMPILER_CLANG_VERSION 0 +# define nssv_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) -#define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +# define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else -#define nssv_COMPILER_GNUC_VERSION 0 +# define nssv_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): -#define nssv_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi)) +#define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Presence of language and library features: #ifdef _HAS_CPP0X -#define nssv_HAS_CPP0X _HAS_CPP0X +# define nssv_HAS_CPP0X _HAS_CPP0X #else -#define nssv_HAS_CPP0X 0 +# define nssv_HAS_CPP0X 0 #endif // Unless defined otherwise below, consider VC14 as C++11 for variant-lite: #if nssv_COMPILER_MSVC_VER >= 1900 -#undef nssv_CPP11_OR_GREATER -#define nssv_CPP11_OR_GREATER 1 +# undef nssv_CPP11_OR_GREATER +# define nssv_CPP11_OR_GREATER 1 #endif -#define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500) -#define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600) -#define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700) -#define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800) -#define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900) -#define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910) +#define nssv_CPP11_90 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500) +#define nssv_CPP11_100 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600) +#define nssv_CPP11_110 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700) +#define nssv_CPP11_120 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800) +#define nssv_CPP11_140 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900) +#define nssv_CPP11_141 (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910) -#define nssv_CPP14_000 (nssv_CPP14_OR_GREATER) -#define nssv_CPP17_000 (nssv_CPP17_OR_GREATER) +#define nssv_CPP14_000 (nssv_CPP14_OR_GREATER) +#define nssv_CPP17_000 (nssv_CPP17_OR_GREATER) // Presence of C++11 language features: -#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140 -#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140 -#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140 -#define nssv_HAVE_NOEXCEPT nssv_CPP11_140 -#define nssv_HAVE_NULLPTR nssv_CPP11_100 -#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140 -#define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140 +#define nssv_HAVE_CONSTEXPR_11 nssv_CPP11_140 +#define nssv_HAVE_EXPLICIT_CONVERSION nssv_CPP11_140 +#define nssv_HAVE_INLINE_NAMESPACE nssv_CPP11_140 +#define nssv_HAVE_NOEXCEPT nssv_CPP11_140 +#define nssv_HAVE_NULLPTR nssv_CPP11_100 +#define nssv_HAVE_REF_QUALIFIER nssv_CPP11_140 +#define nssv_HAVE_UNICODE_LITERALS nssv_CPP11_140 #define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140 -#define nssv_HAVE_WCHAR16_T nssv_CPP11_100 -#define nssv_HAVE_WCHAR32_T nssv_CPP11_100 +#define nssv_HAVE_WCHAR16_T nssv_CPP11_100 +#define nssv_HAVE_WCHAR32_T nssv_CPP11_100 -#if !((nssv_CPP11 && nssv_COMPILER_CLANG_VERSION) || nssv_BETWEEN(nssv_COMPILER_CLANG_VERSION, 300, 400)) -#define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140 +#if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) ) +# define nssv_HAVE_STD_DEFINED_LITERALS nssv_CPP11_140 #endif // Presence of C++14 language features: -#define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000 +#define nssv_HAVE_CONSTEXPR_14 nssv_CPP14_000 // Presence of C++17 language features: -#define nssv_HAVE_NODISCARD nssv_CPP17_000 +#define nssv_HAVE_NODISCARD nssv_CPP17_000 // Presence of C++ library features: -#define nssv_HAVE_STD_HASH nssv_CPP11_120 +#define nssv_HAVE_STD_HASH nssv_CPP11_120 // C++ feature usage: #if nssv_HAVE_CONSTEXPR_11 -#define nssv_constexpr constexpr +# define nssv_constexpr constexpr #else -#define nssv_constexpr /*constexpr*/ +# define nssv_constexpr /*constexpr*/ #endif -#if nssv_HAVE_CONSTEXPR_14 -#define nssv_constexpr14 constexpr +#if nssv_HAVE_CONSTEXPR_14 +# define nssv_constexpr14 constexpr #else -#define nssv_constexpr14 /*constexpr*/ +# define nssv_constexpr14 /*constexpr*/ #endif #if nssv_HAVE_EXPLICIT_CONVERSION -#define nssv_explicit explicit +# define nssv_explicit explicit #else -#define nssv_explicit /*explicit*/ +# define nssv_explicit /*explicit*/ #endif #if nssv_HAVE_INLINE_NAMESPACE -#define nssv_inline_ns inline +# define nssv_inline_ns inline #else -#define nssv_inline_ns /*inline*/ +# define nssv_inline_ns /*inline*/ #endif #if nssv_HAVE_NOEXCEPT -#define nssv_noexcept noexcept +# define nssv_noexcept noexcept #else -#define nssv_noexcept /*noexcept*/ +# define nssv_noexcept /*noexcept*/ #endif //#if nssv_HAVE_REF_QUALIFIER @@ -2289,15 +2176,15 @@ namespace nonstd //#endif #if nssv_HAVE_NULLPTR -#define nssv_nullptr nullptr +# define nssv_nullptr nullptr #else -#define nssv_nullptr NULL +# define nssv_nullptr NULL #endif #if nssv_HAVE_NODISCARD -#define nssv_nodiscard [[nodiscard]] +# define nssv_nodiscard [[nodiscard]] #else -#define nssv_nodiscard /*[[nodiscard]]*/ +# define nssv_nodiscard /*[[nodiscard]]*/ #endif // Additional includes: @@ -2307,45 +2194,45 @@ namespace nonstd #include #include #include -#include // std::char_traits<> +#include // std::char_traits<> -#if !nssv_CONFIG_NO_EXCEPTIONS -#include +#if ! nssv_CONFIG_NO_EXCEPTIONS +# include #endif #if nssv_CPP11_OR_GREATER -#include +# include #endif // Clang, GNUC, MSVC warning suppression macros: #if defined(__clang__) -#pragma clang diagnostic ignored "-Wreserved-user-defined-literal" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wuser-defined-literals" +# pragma clang diagnostic ignored "-Wreserved-user-defined-literal" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wuser-defined-literals" #elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wliteral-suffix" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wliteral-suffix" #endif // __clang__ #if nssv_COMPILER_MSVC_VERSION >= 140 -#define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] -#define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress : code)) -#define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable : codes)) +# define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]] +# define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) ) +# define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes)) #else -#define nssv_SUPPRESS_MSGSL_WARNING(expr) -#define nssv_SUPPRESS_MSVC_WARNING(code, descr) -#define nssv_DISABLE_MSVC_WARNINGS(codes) +# define nssv_SUPPRESS_MSGSL_WARNING(expr) +# define nssv_SUPPRESS_MSVC_WARNING(code, descr) +# define nssv_DISABLE_MSVC_WARNINGS(codes) #endif #if defined(__clang__) -#define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +# define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") #elif defined(__GNUC__) -#define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") #elif nssv_COMPILER_MSVC_VERSION >= 140 -#define nssv_RESTORE_WARNINGS() __pragma(warning(pop)) +# define nssv_RESTORE_WARNINGS() __pragma(warning(pop )) #else -#define nssv_RESTORE_WARNINGS() +# define nssv_RESTORE_WARNINGS() #endif // Suppress the following MSVC (GSL) warnings: @@ -2355,763 +2242,722 @@ namespace nonstd // use brace initialization, gsl::narrow_cast or gsl::narow // - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead -nssv_DISABLE_MSVC_WARNINGS(4455 26481 26472) - // nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" ) - // nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix ) +nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 ) +//nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" ) +//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix ) - namespace nonstd -{ - namespace sv_lite - { +namespace nonstd { namespace sv_lite { - template> - class basic_string_view; +template +< + class CharT, + class Traits = std::char_traits +> +class basic_string_view; - // - // basic_string_view: - // +// +// basic_string_view: +// - template< - class CharT, - class Traits /* = std::char_traits */ - > - class basic_string_view - { - public: - // Member types: +template +< + class CharT, + class Traits /* = std::char_traits */ +> +class basic_string_view +{ +public: + // Member types: - typedef Traits traits_type; - typedef CharT value_type; + typedef Traits traits_type; + typedef CharT value_type; - typedef CharT* pointer; - typedef CharT const* const_pointer; - typedef CharT& reference; - typedef CharT const& const_reference; + typedef CharT * pointer; + typedef CharT const * const_pointer; + typedef CharT & reference; + typedef CharT const & const_reference; - typedef const_pointer iterator; - typedef const_pointer const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; + typedef const_pointer iterator; + typedef const_pointer const_iterator; + typedef std::reverse_iterator< const_iterator > reverse_iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - // 24.4.2.1 Construction and assignment: + // 24.4.2.1 Construction and assignment: - nssv_constexpr basic_string_view() nssv_noexcept - : data_(nssv_nullptr) - , size_(0) - { - } + nssv_constexpr basic_string_view() nssv_noexcept + : data_( nssv_nullptr ) + , size_( 0 ) + {} #if nssv_CPP11_OR_GREATER - nssv_constexpr basic_string_view(basic_string_view const& other) nssv_noexcept = default; + nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default; #else - nssv_constexpr basic_string_view(basic_string_view const& other) nssv_noexcept - : data_(other.data_) - , size_(other.size_) - { - } + nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept + : data_( other.data_) + , size_( other.size_) + {} #endif - nssv_constexpr basic_string_view(CharT const* s, size_type count) - : data_(s) - , size_(count) - { - } + nssv_constexpr basic_string_view( CharT const * s, size_type count ) + : data_( s ) + , size_( count ) + {} - nssv_constexpr basic_string_view(CharT const* s) - : data_(s) - , size_(Traits::length(s)) - { - } + nssv_constexpr basic_string_view( CharT const * s) + : data_( s ) + , size_( Traits::length(s) ) + {} - // Assignment: + // Assignment: #if nssv_CPP11_OR_GREATER - nssv_constexpr14 basic_string_view& operator=(basic_string_view const& other) nssv_noexcept = default; + nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default; #else - nssv_constexpr14 basic_string_view& operator=(basic_string_view const& other) nssv_noexcept - { - data_ = other.data_; - size_ = other.size_; - return *this; - } + nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept + { + data_ = other.data_; + size_ = other.size_; + return *this; + } #endif - // 24.4.2.2 Iterator support: + // 24.4.2.2 Iterator support: - nssv_constexpr const_iterator begin() const nssv_noexcept - { - return data_; - } - nssv_constexpr const_iterator end() const nssv_noexcept - { - return data_ + size_; - } + nssv_constexpr const_iterator begin() const nssv_noexcept { return data_; } + nssv_constexpr const_iterator end() const nssv_noexcept { return data_ + size_; } - nssv_constexpr const_iterator cbegin() const nssv_noexcept - { - return begin(); - } - nssv_constexpr const_iterator cend() const nssv_noexcept - { - return end(); - } + nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); } + nssv_constexpr const_iterator cend() const nssv_noexcept { return end(); } - nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept - { - return const_reverse_iterator(end()); - } - nssv_constexpr const_reverse_iterator rend() const nssv_noexcept - { - return const_reverse_iterator(begin()); - } + nssv_constexpr const_reverse_iterator rbegin() const nssv_noexcept { return const_reverse_iterator( end() ); } + nssv_constexpr const_reverse_iterator rend() const nssv_noexcept { return const_reverse_iterator( begin() ); } - nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept - { - return rbegin(); - } - nssv_constexpr const_reverse_iterator crend() const nssv_noexcept - { - return rend(); - } + nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); } + nssv_constexpr const_reverse_iterator crend() const nssv_noexcept { return rend(); } - // 24.4.2.3 Capacity: + // 24.4.2.3 Capacity: - nssv_constexpr size_type size() const nssv_noexcept - { - return size_; - } - nssv_constexpr size_type length() const nssv_noexcept - { - return size_; - } - nssv_constexpr size_type max_size() const nssv_noexcept - { - return (std::numeric_limits::max)(); - } + nssv_constexpr size_type size() const nssv_noexcept { return size_; } + nssv_constexpr size_type length() const nssv_noexcept { return size_; } + nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); } - // since C++20 - nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept - { - return 0 == size_; - } + // since C++20 + nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept + { + return 0 == size_; + } - // 24.4.2.4 Element access: + // 24.4.2.4 Element access: - nssv_constexpr const_reference operator[](size_type pos) const - { - return data_at(pos); - } + nssv_constexpr const_reference operator[]( size_type pos ) const + { + return data_at( pos ); + } - nssv_constexpr14 const_reference at(size_type pos) const - { + nssv_constexpr14 const_reference at( size_type pos ) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert(pos < size()); + assert( pos < size() ); #else - if (pos >= size()) - { - throw std::out_of_range("nonst::string_view::at()"); - } + if ( pos >= size() ) + { + throw std::out_of_range("nonst::string_view::at()"); + } #endif - return data_at(pos); - } + return data_at( pos ); + } - nssv_constexpr const_reference front() const - { - return data_at(0); - } - nssv_constexpr const_reference back() const - { - return data_at(size() - 1); - } + nssv_constexpr const_reference front() const { return data_at( 0 ); } + nssv_constexpr const_reference back() const { return data_at( size() - 1 ); } - nssv_constexpr const_pointer data() const nssv_noexcept - { - return data_; - } + nssv_constexpr const_pointer data() const nssv_noexcept { return data_; } - // 24.4.2.5 Modifiers: + // 24.4.2.5 Modifiers: - nssv_constexpr14 void remove_prefix(size_type n) - { - assert(n <= size()); - data_ += n; - size_ -= n; - } + nssv_constexpr14 void remove_prefix( size_type n ) + { + assert( n <= size() ); + data_ += n; + size_ -= n; + } - nssv_constexpr14 void remove_suffix(size_type n) - { - assert(n <= size()); - size_ -= n; - } + nssv_constexpr14 void remove_suffix( size_type n ) + { + assert( n <= size() ); + size_ -= n; + } - nssv_constexpr14 void swap(basic_string_view& other) nssv_noexcept - { - using std::swap; - swap(data_, other.data_); - swap(size_, other.size_); - } + nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept + { + using std::swap; + swap( data_, other.data_ ); + swap( size_, other.size_ ); + } - // 24.4.2.6 String operations: + // 24.4.2.6 String operations: - size_type copy(CharT* dest, size_type n, size_type pos = 0) const - { + size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert(pos <= size()); + assert( pos <= size() ); #else - if (pos > size()) - { - throw std::out_of_range("nonst::string_view::copy()"); - } + if ( pos > size() ) + { + throw std::out_of_range("nonst::string_view::copy()"); + } #endif - const size_type rlen = (std::min)(n, size() - pos); + const size_type rlen = (std::min)( n, size() - pos ); - (void)Traits::copy(dest, data() + pos, rlen); + (void) Traits::copy( dest, data() + pos, rlen ); - return rlen; - } + return rlen; + } - nssv_constexpr14 basic_string_view substr(size_type pos = 0, size_type n = npos) const - { + nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const + { #if nssv_CONFIG_NO_EXCEPTIONS - assert(pos <= size()); + assert( pos <= size() ); #else - if (pos > size()) - { - throw std::out_of_range("nonst::string_view::substr()"); - } + if ( pos > size() ) + { + throw std::out_of_range("nonst::string_view::substr()"); + } #endif - return basic_string_view(data() + pos, (std::min)(n, size() - pos)); - } - - // compare(), 6x: - - nssv_constexpr14 int compare(basic_string_view other) const nssv_noexcept // (1) - { - if (const int result = Traits::compare(data(), other.data(), (std::min)(size(), other.size()))) - return result; - - return size() == other.size() ? 0 : size() < other.size() ? -1 : 1; - } - - nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other) const // (2) - { - return substr(pos1, n1).compare(other); - } - - nssv_constexpr int compare(size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2) const // (3) - { - return substr(pos1, n1).compare(other.substr(pos2, n2)); - } - - nssv_constexpr int compare(CharT const* s) const // (4) - { - return compare(basic_string_view(s)); - } - - nssv_constexpr int compare(size_type pos1, size_type n1, CharT const* s) const // (5) - { - return substr(pos1, n1).compare(basic_string_view(s)); - } - - nssv_constexpr int compare(size_type pos1, size_type n1, CharT const* s, size_type n2) const // (6) - { - return substr(pos1, n1).compare(basic_string_view(s, n2)); - } - - // 24.4.2.7 Searching: - - // starts_with(), 3x, since C++20: - - nssv_constexpr bool starts_with(basic_string_view v) const nssv_noexcept // (1) - { - return size() >= v.size() && compare(0, v.size(), v) == 0; - } - - nssv_constexpr bool starts_with(CharT c) const nssv_noexcept // (2) - { - return starts_with(basic_string_view(&c, 1)); - } - - nssv_constexpr bool starts_with(CharT const* s) const // (3) - { - return starts_with(basic_string_view(s)); - } - - // ends_with(), 3x, since C++20: - - nssv_constexpr bool ends_with(basic_string_view v) const nssv_noexcept // (1) - { - return size() >= v.size() && compare(size() - v.size(), npos, v) == 0; - } - - nssv_constexpr bool ends_with(CharT c) const nssv_noexcept // (2) - { - return ends_with(basic_string_view(&c, 1)); - } - - nssv_constexpr bool ends_with(CharT const* s) const // (3) - { - return ends_with(basic_string_view(s)); - } - - // find(), 4x: - - nssv_constexpr14 size_type find(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) - { - return assert(v.size() == 0 || v.data() != nssv_nullptr), - pos >= size() ? npos : to_pos(std::search(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq)); - } - - nssv_constexpr14 size_type find(CharT c, size_type pos = 0) const nssv_noexcept // (2) - { - return find(basic_string_view(&c, 1), pos); - } - - nssv_constexpr14 size_type find(CharT const* s, size_type pos, size_type n) const // (3) - { - return find(basic_string_view(s, n), pos); - } - - nssv_constexpr14 size_type find(CharT const* s, size_type pos = 0) const // (4) - { - return find(basic_string_view(s), pos); - } - - // rfind(), 4x: - - nssv_constexpr14 size_type rfind(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) - { - if (size() < v.size()) - return npos; - - if (v.empty()) - return (std::min)(size(), pos); - - const_iterator last = cbegin() + (std::min)(size() - v.size(), pos) + v.size(); - const_iterator result = std::find_end(cbegin(), last, v.cbegin(), v.cend(), Traits::eq); - - return result != last ? size_type(result - cbegin()) : npos; - } - - nssv_constexpr14 size_type rfind(CharT c, size_type pos = npos) const nssv_noexcept // (2) - { - return rfind(basic_string_view(&c, 1), pos); - } - - nssv_constexpr14 size_type rfind(CharT const* s, size_type pos, size_type n) const // (3) - { - return rfind(basic_string_view(s, n), pos); - } - - nssv_constexpr14 size_type rfind(CharT const* s, size_type pos = npos) const // (4) - { - return rfind(basic_string_view(s), pos); - } - - // find_first_of(), 4x: - - nssv_constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) - { - return pos >= size() ? npos : to_pos(std::find_first_of(cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq)); - } + return basic_string_view( data() + pos, (std::min)( n, size() - pos ) ); + } - nssv_constexpr size_type find_first_of(CharT c, size_type pos = 0) const nssv_noexcept // (2) - { - return find_first_of(basic_string_view(&c, 1), pos); - } + // compare(), 6x: - nssv_constexpr size_type find_first_of(CharT const* s, size_type pos, size_type n) const // (3) - { - return find_first_of(basic_string_view(s, n), pos); - } + nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1) + { + if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) ) + return result; - nssv_constexpr size_type find_first_of(CharT const* s, size_type pos = 0) const // (4) - { - return find_first_of(basic_string_view(s), pos); - } + return size() == other.size() ? 0 : size() < other.size() ? -1 : 1; + } - // find_last_of(), 4x: + nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2) + { + return substr( pos1, n1 ).compare( other ); + } - nssv_constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) - { - return empty() ? npos - : pos >= size() - ? find_last_of(v, size() - 1) - : to_pos(std::find_first_of(const_reverse_iterator(cbegin() + pos + 1), crend(), v.cbegin(), v.cend(), Traits::eq)); - } + nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3) + { + return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) ); + } - nssv_constexpr size_type find_last_of(CharT c, size_type pos = npos) const nssv_noexcept // (2) - { - return find_last_of(basic_string_view(&c, 1), pos); - } + nssv_constexpr int compare( CharT const * s ) const // (4) + { + return compare( basic_string_view( s ) ); + } - nssv_constexpr size_type find_last_of(CharT const* s, size_type pos, size_type count) const // (3) - { - return find_last_of(basic_string_view(s, count), pos); - } + nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5) + { + return substr( pos1, n1 ).compare( basic_string_view( s ) ); + } - nssv_constexpr size_type find_last_of(CharT const* s, size_type pos = npos) const // (4) - { - return find_last_of(basic_string_view(s), pos); - } + nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6) + { + return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) ); + } - // find_first_not_of(), 4x: + // 24.4.2.7 Searching: - nssv_constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) const nssv_noexcept // (1) - { - return pos >= size() ? npos : to_pos(std::find_if(cbegin() + pos, cend(), not_in_view(v))); - } + // starts_with(), 3x, since C++20: - nssv_constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const nssv_noexcept // (2) - { - return find_first_not_of(basic_string_view(&c, 1), pos); - } + nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept // (1) + { + return size() >= v.size() && compare( 0, v.size(), v ) == 0; + } - nssv_constexpr size_type find_first_not_of(CharT const* s, size_type pos, size_type count) const // (3) - { - return find_first_not_of(basic_string_view(s, count), pos); - } + nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept // (2) + { + return starts_with( basic_string_view( &c, 1 ) ); + } - nssv_constexpr size_type find_first_not_of(CharT const* s, size_type pos = 0) const // (4) - { - return find_first_not_of(basic_string_view(s), pos); - } + nssv_constexpr bool starts_with( CharT const * s ) const // (3) + { + return starts_with( basic_string_view( s ) ); + } - // find_last_not_of(), 4x: + // ends_with(), 3x, since C++20: - nssv_constexpr size_type find_last_not_of(basic_string_view v, size_type pos = npos) const nssv_noexcept // (1) - { - return empty() ? npos - : pos >= size() ? find_last_not_of(v, size() - 1) - : to_pos(std::find_if(const_reverse_iterator(cbegin() + pos + 1), crend(), not_in_view(v))); - } + nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept // (1) + { + return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0; + } - nssv_constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const nssv_noexcept // (2) - { - return find_last_not_of(basic_string_view(&c, 1), pos); - } + nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept // (2) + { + return ends_with( basic_string_view( &c, 1 ) ); + } - nssv_constexpr size_type find_last_not_of(CharT const* s, size_type pos, size_type count) const // (3) - { - return find_last_not_of(basic_string_view(s, count), pos); - } + nssv_constexpr bool ends_with( CharT const * s ) const // (3) + { + return ends_with( basic_string_view( s ) ); + } - nssv_constexpr size_type find_last_not_of(CharT const* s, size_type pos = npos) const // (4) - { - return find_last_not_of(basic_string_view(s), pos); - } + // find(), 4x: - // Constants: + nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) + { + return assert( v.size() == 0 || v.data() != nssv_nullptr ) + , pos >= size() + ? npos + : to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); + } -#if nssv_CPP17_OR_GREATER - static nssv_constexpr size_type npos = size_type(-1); -#elif nssv_CPP11_OR_GREATER - enum : size_type - { - npos = size_type(-1) - }; -#else - enum - { - npos = size_type(-1) - }; -#endif + nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) + { + return find( basic_string_view( &c, 1 ), pos ); + } - private: - struct not_in_view - { - const basic_string_view v; + nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const // (3) + { + return find( basic_string_view( s, n ), pos ); + } - nssv_constexpr not_in_view(basic_string_view v) - : v(v) - { - } + nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const // (4) + { + return find( basic_string_view( s ), pos ); + } - nssv_constexpr bool operator()(CharT c) const - { - return npos == v.find_first_of(c); - } - }; + // rfind(), 4x: - nssv_constexpr size_type to_pos(const_iterator it) const - { - return it == cend() ? npos : size_type(it - cbegin()); - } + nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) + { + if ( size() < v.size() ) + return npos; - nssv_constexpr size_type to_pos(const_reverse_iterator it) const - { - return it == crend() ? npos : size_type(crend() - it - 1); - } + if ( v.empty() ) + return (std::min)( size(), pos ); - nssv_constexpr const_reference data_at(size_type pos) const - { -#if nssv_BETWEEN(nssv_COMPILER_GNUC_VERSION, 1, 500) - return data_[pos]; -#else - return assert(pos < size()), data_[pos]; -#endif - } + const_iterator last = cbegin() + (std::min)( size() - v.size(), pos ) + v.size(); + const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq ); - private: - const_pointer data_; - size_type size_; + return result != last ? size_type( result - cbegin() ) : npos; + } - public: -#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS + nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept // (2) + { + return rfind( basic_string_view( &c, 1 ), pos ); + } - template - basic_string_view(std::basic_string const& s) nssv_noexcept - : data_(s.data()) - , size_(s.size()) - { - } + nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const // (3) + { + return rfind( basic_string_view( s, n ), pos ); + } -#if nssv_HAVE_EXPLICIT_CONVERSION + nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const // (4) + { + return rfind( basic_string_view( s ), pos ); + } - template - explicit operator std::basic_string() const - { - return to_string(Allocator()); - } + // find_first_of(), 4x: -#endif // nssv_HAVE_EXPLICIT_CONVERSION + nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) + { + return pos >= size() + ? npos + : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) ); + } -#if nssv_CPP11_OR_GREATER + nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) + { + return find_first_of( basic_string_view( &c, 1 ), pos ); + } - template> - std::basic_string to_string(Allocator const& a = Allocator()) const - { - return std::basic_string(begin(), end(), a); - } + nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const // (3) + { + return find_first_of( basic_string_view( s, n ), pos ); + } -#else + nssv_constexpr size_type find_first_of( CharT const * s, size_type pos = 0 ) const // (4) + { + return find_first_of( basic_string_view( s ), pos ); + } - std::basic_string to_string() const - { - return std::basic_string(begin(), end()); - } + // find_last_of(), 4x: - template - std::basic_string to_string(Allocator const& a) const - { - return std::basic_string(begin(), end(), a); - } + nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) + { + return empty() + ? npos + : pos >= size() + ? find_last_of( v, size() - 1 ) + : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) ); + } -#endif // nssv_CPP11_OR_GREATER + nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) + { + return find_last_of( basic_string_view( &c, 1 ), pos ); + } -#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS - }; + nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const // (3) + { + return find_last_of( basic_string_view( s, count ), pos ); + } - // - // Non-member functions: - // + nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const // (4) + { + return find_last_of( basic_string_view( s ), pos ); + } - // 24.4.3 Non-member comparison functions: - // lexicographically compare two string views (function template): + // find_first_not_of(), 4x: - template - nssv_constexpr bool operator==(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) == 0; - } + nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1) + { + return pos >= size() + ? npos + : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) ); + } - template - nssv_constexpr bool operator!=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) != 0; - } + nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept // (2) + { + return find_first_not_of( basic_string_view( &c, 1 ), pos ); + } - template - nssv_constexpr bool operator<(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) < 0; - } + nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const // (3) + { + return find_first_not_of( basic_string_view( s, count ), pos ); + } - template - nssv_constexpr bool operator<=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) <= 0; - } + nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const // (4) + { + return find_first_not_of( basic_string_view( s ), pos ); + } - template - nssv_constexpr bool operator>(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) > 0; - } + // find_last_not_of(), 4x: - template - nssv_constexpr bool operator>=(basic_string_view lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) >= 0; - } + nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept // (1) + { + return empty() + ? npos + : pos >= size() + ? find_last_not_of( v, size() - 1 ) + : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) ); + } + + nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept // (2) + { + return find_last_not_of( basic_string_view( &c, 1 ), pos ); + } - // Let S be basic_string_view, and sv be an instance of S. - // Implementations shall provide sufficient additional overloads marked - // constexpr and noexcept so that an object t with an implicit conversion - // to S can be compared according to Table 67. + nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const // (3) + { + return find_last_not_of( basic_string_view( s, count ), pos ); + } -#if nssv_CPP11_OR_GREATER && !nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 100, 141) + nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const // (4) + { + return find_last_not_of( basic_string_view( s ), pos ); + } -#define nssv_BASIC_STRING_VIEW_I(T, U) typename std::decay>::type + // Constants: -#if nssv_BETWEEN(nssv_COMPILER_MSVC_VERSION, 140, 150) -#define nssv_MSVC_ORDER(x) , int = x +#if nssv_CPP17_OR_GREATER + static nssv_constexpr size_type npos = size_type(-1); +#elif nssv_CPP11_OR_GREATER + enum : size_type { npos = size_type(-1) }; #else -#define nssv_MSVC_ORDER(x) /*, int=x*/ + enum { npos = size_type(-1) }; #endif - // == +private: + struct not_in_view + { + const basic_string_view v; - template - nssv_constexpr bool operator==(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.compare(rhs) == 0; - } + nssv_constexpr not_in_view( basic_string_view v ) : v( v ) {} - template - nssv_constexpr bool operator==(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept + nssv_constexpr bool operator()( CharT c ) const { - return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; + return npos == v.find_first_of( c ); } + }; - // != + nssv_constexpr size_type to_pos( const_iterator it ) const + { + return it == cend() ? npos : size_type( it - cbegin() ); + } - template - nssv_constexpr bool operator!=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.size() != rhs.size() || lhs.compare(rhs) != 0; - } + nssv_constexpr size_type to_pos( const_reverse_iterator it ) const + { + return it == crend() ? npos : size_type( crend() - it - 1 ); + } - template - nssv_constexpr bool operator!=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) != 0; - } + nssv_constexpr const_reference data_at( size_type pos ) const + { +#if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 ) + return data_[pos]; +#else + return assert( pos < size() ), data_[pos]; +#endif + } - // < +private: + const_pointer data_; + size_type size_; - template - nssv_constexpr bool operator<(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.compare(rhs) < 0; - } +public: +#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS - template - nssv_constexpr bool operator<(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) < 0; - } + template< class Allocator > + basic_string_view( std::basic_string const & s ) nssv_noexcept + : data_( s.data() ) + , size_( s.size() ) + {} - // <= +#if nssv_HAVE_EXPLICIT_CONVERSION - template - nssv_constexpr bool operator<=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.compare(rhs) <= 0; - } + template< class Allocator > + explicit operator std::basic_string() const + { + return to_string( Allocator() ); + } - template - nssv_constexpr bool operator<=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) <= 0; - } +#endif // nssv_HAVE_EXPLICIT_CONVERSION - // > +#if nssv_CPP11_OR_GREATER - template - nssv_constexpr bool operator>(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.compare(rhs) > 0; - } + template< class Allocator = std::allocator > + std::basic_string + to_string( Allocator const & a = Allocator() ) const + { + return std::basic_string( begin(), end(), a ); + } - template - nssv_constexpr bool operator>(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) > 0; - } +#else - // >= + std::basic_string + to_string() const + { + return std::basic_string( begin(), end() ); + } - template - nssv_constexpr bool operator>=(basic_string_view lhs, nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs) nssv_noexcept - { - return lhs.compare(rhs) >= 0; - } + template< class Allocator > + std::basic_string + to_string( Allocator const & a ) const + { + return std::basic_string( begin(), end(), a ); + } - template - nssv_constexpr bool operator>=(nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, basic_string_view rhs) nssv_noexcept - { - return lhs.compare(rhs) >= 0; - } +#endif // nssv_CPP11_OR_GREATER + +#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS +}; + +// +// Non-member functions: +// + +// 24.4.3 Non-member comparison functions: +// lexicographically compare two string views (function template): + +template< class CharT, class Traits > +nssv_constexpr bool operator== ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) == 0 ; } + +template< class CharT, class Traits > +nssv_constexpr bool operator!= ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) != 0 ; } + +template< class CharT, class Traits > +nssv_constexpr bool operator< ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) < 0 ; } + +template< class CharT, class Traits > +nssv_constexpr bool operator<= ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) <= 0 ; } + +template< class CharT, class Traits > +nssv_constexpr bool operator> ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) > 0 ; } + +template< class CharT, class Traits > +nssv_constexpr bool operator>= ( + basic_string_view lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.compare( rhs ) >= 0 ; } + +// Let S be basic_string_view, and sv be an instance of S. +// Implementations shall provide sufficient additional overloads marked +// constexpr and noexcept so that an object t with an implicit conversion +// to S can be compared according to Table 67. + +#if nssv_CPP11_OR_GREATER && ! nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 ) + +#define nssv_BASIC_STRING_VIEW_I(T,U) typename std::decay< basic_string_view >::type + +#if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 ) +# define nssv_MSVC_ORDER(x) , int=x +#else +# define nssv_MSVC_ORDER(x) /*, int=x*/ +#endif + +// == + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator==( + basic_string_view lhs, + nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept +{ return lhs.compare( rhs ) == 0; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator==( + nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs, + basic_string_view rhs ) nssv_noexcept +{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; } + +// != + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator!= ( + basic_string_view < CharT, Traits > lhs, + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept +{ return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator!= ( + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, + basic_string_view < CharT, Traits > rhs ) nssv_noexcept +{ return lhs.compare( rhs ) != 0 ; } + +// < + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator< ( + basic_string_view < CharT, Traits > lhs, + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept +{ return lhs.compare( rhs ) < 0 ; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator< ( + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, + basic_string_view < CharT, Traits > rhs ) nssv_noexcept +{ return lhs.compare( rhs ) < 0 ; } + +// <= + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator<= ( + basic_string_view < CharT, Traits > lhs, + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept +{ return lhs.compare( rhs ) <= 0 ; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator<= ( + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, + basic_string_view < CharT, Traits > rhs ) nssv_noexcept +{ return lhs.compare( rhs ) <= 0 ; } + +// > + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator> ( + basic_string_view < CharT, Traits > lhs, + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept +{ return lhs.compare( rhs ) > 0 ; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator> ( + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, + basic_string_view < CharT, Traits > rhs ) nssv_noexcept +{ return lhs.compare( rhs ) > 0 ; } + +// >= + +template< class CharT, class Traits nssv_MSVC_ORDER(1) > +nssv_constexpr bool operator>= ( + basic_string_view < CharT, Traits > lhs, + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept +{ return lhs.compare( rhs ) >= 0 ; } + +template< class CharT, class Traits nssv_MSVC_ORDER(2) > +nssv_constexpr bool operator>= ( + nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs, + basic_string_view < CharT, Traits > rhs ) nssv_noexcept +{ return lhs.compare( rhs ) >= 0 ; } #undef nssv_MSVC_ORDER #undef nssv_BASIC_STRING_VIEW_I #endif // nssv_CPP11_OR_GREATER - // 24.4.4 Inserters and extractors: +// 24.4.4 Inserters and extractors: - namespace detail - { +namespace detail { - template - void write_padding(Stream& os, std::streamsize n) - { - for (std::streamsize i = 0; i < n; ++i) - os.rdbuf()->sputc(os.fill()); - } +template< class Stream > +void write_padding( Stream & os, std::streamsize n ) +{ + for ( std::streamsize i = 0; i < n; ++i ) + os.rdbuf()->sputc( os.fill() ); +} - template - Stream& write_to_stream(Stream& os, View const& sv) - { - typename Stream::sentry sentry(os); +template< class Stream, class View > +Stream & write_to_stream( Stream & os, View const & sv ) +{ + typename Stream::sentry sentry( os ); - if (!os) - return os; + if ( !os ) + return os; - const std::streamsize length = static_cast(sv.length()); + const std::streamsize length = static_cast( sv.length() ); - // Whether, and how, to pad: - const bool pad = (length < os.width()); - const bool left_pad = pad && (os.flags() & std::ios_base::adjustfield) == std::ios_base::right; + // Whether, and how, to pad: + const bool pad = ( length < os.width() ); + const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right; - if (left_pad) - write_padding(os, os.width() - length); + if ( left_pad ) + write_padding( os, os.width() - length ); - // Write span characters: - os.rdbuf()->sputn(sv.begin(), length); + // Write span characters: + os.rdbuf()->sputn( sv.begin(), length ); - if (pad && !left_pad) - write_padding(os, os.width() - length); + if ( pad && !left_pad ) + write_padding( os, os.width() - length ); - // Reset output stream width: - os.width(0); + // Reset output stream width: + os.width( 0 ); - return os; - } + return os; +} - } // namespace detail +} // namespace detail - template - std::basic_ostream& operator<<(std::basic_ostream& os, basic_string_view sv) - { - return detail::write_to_stream(os, sv); - } +template< class CharT, class Traits > +std::basic_ostream & +operator<<( + std::basic_ostream& os, + basic_string_view sv ) +{ + return detail::write_to_stream( os, sv ); +} - // Several typedefs for common character types are provided: +// Several typedefs for common character types are provided: - typedef basic_string_view string_view; - typedef basic_string_view wstring_view; +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; #if nssv_HAVE_WCHAR16_T - typedef basic_string_view u16string_view; - typedef basic_string_view u32string_view; +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; #endif - } // namespace sv_lite -} // namespace nonstd::sv_lite +}} // namespace nonstd::sv_lite // // 24.4.6 Suffix for basic_string_view literals: @@ -3119,63 +2965,59 @@ nssv_DISABLE_MSVC_WARNINGS(4455 26481 26472) #if nssv_HAVE_USER_DEFINED_LITERALS -namespace nonstd -{ - nssv_inline_ns namespace literals - { - nssv_inline_ns namespace string_view_literals - { +namespace nonstd { +nssv_inline_ns namespace literals { +nssv_inline_ns namespace string_view_literals { #if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS - nssv_constexpr nonstd::sv_lite::string_view operator"" sv(const char* str, size_t len) nssv_noexcept // (1) - { - return nonstd::sv_lite::string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1) +{ + return nonstd::sv_lite::string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::u16string_view operator"" sv(const char16_t* str, size_t len) nssv_noexcept // (2) - { - return nonstd::sv_lite::u16string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +{ + return nonstd::sv_lite::u16string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::u32string_view operator"" sv(const char32_t* str, size_t len) nssv_noexcept // (3) - { - return nonstd::sv_lite::u32string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +{ + return nonstd::sv_lite::u32string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::wstring_view operator"" sv(const wchar_t* str, size_t len) nssv_noexcept // (4) - { - return nonstd::sv_lite::wstring_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +{ + return nonstd::sv_lite::wstring_view{ str, len }; +} #endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS #if nssv_CONFIG_USR_SV_OPERATOR - nssv_constexpr nonstd::sv_lite::string_view operator"" _sv(const char* str, size_t len) nssv_noexcept // (1) - { - return nonstd::sv_lite::string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1) +{ + return nonstd::sv_lite::string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::u16string_view operator"" _sv(const char16_t* str, size_t len) nssv_noexcept // (2) - { - return nonstd::sv_lite::u16string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2) +{ + return nonstd::sv_lite::u16string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::u32string_view operator"" _sv(const char32_t* str, size_t len) nssv_noexcept // (3) - { - return nonstd::sv_lite::u32string_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3) +{ + return nonstd::sv_lite::u32string_view{ str, len }; +} - nssv_constexpr nonstd::sv_lite::wstring_view operator"" _sv(const wchar_t* str, size_t len) nssv_noexcept // (4) - { - return nonstd::sv_lite::wstring_view{ str, len }; - } +nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4) +{ + return nonstd::sv_lite::wstring_view{ str, len }; +} #endif // nssv_CONFIG_USR_SV_OPERATOR - } - } -} // namespace nonstd + +}}} // namespace nonstd::literals::string_view_literals #endif @@ -3185,45 +3027,46 @@ namespace nonstd #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS -namespace nonstd -{ - namespace sv_lite - { +namespace nonstd { +namespace sv_lite { - // Exclude MSVC 14 (19.00): it yields ambiguous to_string(): +// Exclude MSVC 14 (19.00): it yields ambiguous to_string(): #if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140 - template> - std::basic_string to_string(basic_string_view v, Allocator const& a = Allocator()) - { - return std::basic_string(v.begin(), v.end(), a); - } +template< class CharT, class Traits, class Allocator = std::allocator > +std::basic_string +to_string( basic_string_view v, Allocator const & a = Allocator() ) +{ + return std::basic_string( v.begin(), v.end(), a ); +} #else - template - std::basic_string to_string(basic_string_view v) - { - return std::basic_string(v.begin(), v.end()); - } +template< class CharT, class Traits > +std::basic_string +to_string( basic_string_view v ) +{ + return std::basic_string( v.begin(), v.end() ); +} - template - std::basic_string to_string(basic_string_view v, Allocator const& a) - { - return std::basic_string(v.begin(), v.end(), a); - } +template< class CharT, class Traits, class Allocator > +std::basic_string +to_string( basic_string_view v, Allocator const & a ) +{ + return std::basic_string( v.begin(), v.end(), a ); +} #endif // nssv_CPP11_OR_GREATER - template - basic_string_view to_string_view(std::basic_string const& s) - { - return basic_string_view(s.data(), s.size()); - } +template< class CharT, class Traits, class Allocator > +basic_string_view +to_string_view( std::basic_string const & s ) +{ + return basic_string_view( s.data(), s.size() ); +} - } // namespace sv_lite -} // namespace nonstd +}} // namespace nonstd::sv_lite #endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS @@ -3231,34 +3074,33 @@ namespace nonstd // make types and algorithms available in namespace nonstd: // -namespace nonstd -{ +namespace nonstd { - using sv_lite::basic_string_view; - using sv_lite::string_view; - using sv_lite::wstring_view; +using sv_lite::basic_string_view; +using sv_lite::string_view; +using sv_lite::wstring_view; #if nssv_HAVE_WCHAR16_T - using sv_lite::u16string_view; +using sv_lite::u16string_view; #endif #if nssv_HAVE_WCHAR32_T - using sv_lite::u32string_view; +using sv_lite::u32string_view; #endif - // literal "sv" +// literal "sv" - using sv_lite::operator==; - using sv_lite::operator!=; - using sv_lite::operator<; - using sv_lite::operator<=; - using sv_lite::operator>; - using sv_lite::operator>=; +using sv_lite::operator==; +using sv_lite::operator!=; +using sv_lite::operator<; +using sv_lite::operator<=; +using sv_lite::operator>; +using sv_lite::operator>=; - using sv_lite::operator<<; +using sv_lite::operator<<; #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS - using sv_lite::to_string; - using sv_lite::to_string_view; +using sv_lite::to_string; +using sv_lite::to_string_view; #endif } // namespace nonstd @@ -3272,48 +3114,47 @@ namespace nonstd #include -namespace std -{ +namespace std { - template<> - struct hash +template<> +struct hash< nonstd::string_view > +{ +public: + std::size_t operator()( nonstd::string_view v ) const nssv_noexcept { - public: - std::size_t operator()(nonstd::string_view v) const nssv_noexcept - { - return std::hash()(std::string(v.data(), v.size())); - } - }; + return std::hash()( std::string( v.data(), v.size() ) ); + } +}; - template<> - struct hash +template<> +struct hash< nonstd::wstring_view > +{ +public: + std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept { - public: - std::size_t operator()(nonstd::wstring_view v) const nssv_noexcept - { - return std::hash()(std::wstring(v.data(), v.size())); - } - }; + return std::hash()( std::wstring( v.data(), v.size() ) ); + } +}; - template<> - struct hash +template<> +struct hash< nonstd::u16string_view > +{ +public: + std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept { - public: - std::size_t operator()(nonstd::u16string_view v) const nssv_noexcept - { - return std::hash()(std::u16string(v.data(), v.size())); - } - }; + return std::hash()( std::u16string( v.data(), v.size() ) ); + } +}; - template<> - struct hash +template<> +struct hash< nonstd::u32string_view > +{ +public: + std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept { - public: - std::size_t operator()(nonstd::u32string_view v) const nssv_noexcept - { - return std::hash()(std::u32string(v.data(), v.size())); - } - }; + return std::hash()( std::u32string( v.data(), v.size() ) ); + } +}; } // namespace std @@ -3324,9 +3165,10 @@ nssv_RESTORE_WARNINGS() #endif // nssv_HAVE_STD_STRING_VIEW #endif // NONSTD_SV_LITE_H_INCLUDED -// If there is another version of Hedley, then the newer one -// takes precedence. -// See: https://github.com/nemequ/hedley + + // If there is another version of Hedley, then the newer one + // takes precedence. + // See: https://github.com/nemequ/hedley /* Hedley - https://nemequ.github.io/hedley * Created by Evan Nemerson * @@ -3341,1338 +3183,1500 @@ nssv_RESTORE_WARNINGS() #if !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < 9) #if defined(HEDLEY_VERSION) -#undef HEDLEY_VERSION +# undef HEDLEY_VERSION #endif #define HEDLEY_VERSION 9 #if defined(HEDLEY_STRINGIFY_EX) -#undef HEDLEY_STRINGIFY_EX +# undef HEDLEY_STRINGIFY_EX #endif #define HEDLEY_STRINGIFY_EX(x) #x #if defined(HEDLEY_STRINGIFY) -#undef HEDLEY_STRINGIFY +# undef HEDLEY_STRINGIFY #endif #define HEDLEY_STRINGIFY(x) HEDLEY_STRINGIFY_EX(x) #if defined(HEDLEY_CONCAT_EX) -#undef HEDLEY_CONCAT_EX +# undef HEDLEY_CONCAT_EX #endif -#define HEDLEY_CONCAT_EX(a, b) a##b +#define HEDLEY_CONCAT_EX(a,b) a##b #if defined(HEDLEY_CONCAT) -#undef HEDLEY_CONCAT +# undef HEDLEY_CONCAT #endif -#define HEDLEY_CONCAT(a, b) HEDLEY_CONCAT_EX(a, b) +#define HEDLEY_CONCAT(a,b) HEDLEY_CONCAT_EX(a,b) #if defined(HEDLEY_VERSION_ENCODE) -#undef HEDLEY_VERSION_ENCODE +# undef HEDLEY_VERSION_ENCODE #endif -#define HEDLEY_VERSION_ENCODE(major, minor, revision) (((major)*1000000) + ((minor)*1000) + (revision)) +#define HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) #if defined(HEDLEY_VERSION_DECODE_MAJOR) -#undef HEDLEY_VERSION_DECODE_MAJOR +# undef HEDLEY_VERSION_DECODE_MAJOR #endif #define HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(HEDLEY_VERSION_DECODE_MINOR) -#undef HEDLEY_VERSION_DECODE_MINOR +# undef HEDLEY_VERSION_DECODE_MINOR #endif #define HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(HEDLEY_VERSION_DECODE_REVISION) -#undef HEDLEY_VERSION_DECODE_REVISION +# undef HEDLEY_VERSION_DECODE_REVISION #endif #define HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(HEDLEY_GNUC_VERSION) -#undef HEDLEY_GNUC_VERSION +# undef HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) -#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) -#define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +# define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(HEDLEY_GNUC_VERSION_CHECK) -#undef HEDLEY_GNUC_VERSION_CHECK +# undef HEDLEY_GNUC_VERSION_CHECK #endif #if defined(HEDLEY_GNUC_VERSION) -#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_MSVC_VERSION) -#undef HEDLEY_MSVC_VERSION +# undef HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) -#define HEDLEY_MSVC_VERSION \ - HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) -#define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) -#define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +# define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(HEDLEY_MSVC_VERSION_CHECK) -#undef HEDLEY_MSVC_VERSION_CHECK +# undef HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(_MSC_VER) -#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) -#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) -#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else -#define HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (_MSC_VER >= ((major * 100) + (minor))) +# define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(HEDLEY_INTEL_VERSION) -#undef HEDLEY_INTEL_VERSION +# undef HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) -#define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) -#define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +# define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(HEDLEY_INTEL_VERSION_CHECK) -#undef HEDLEY_INTEL_VERSION_CHECK +# undef HEDLEY_INTEL_VERSION_CHECK #endif #if defined(HEDLEY_INTEL_VERSION) -#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_PGI_VERSION) -#undef HEDLEY_PGI_VERSION +# undef HEDLEY_PGI_VERSION #endif #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) -#define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +# define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(HEDLEY_PGI_VERSION_CHECK) -#undef HEDLEY_PGI_VERSION_CHECK +# undef HEDLEY_PGI_VERSION_CHECK #endif #if defined(HEDLEY_PGI_VERSION) -#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_SUNPRO_VERSION) -#undef HEDLEY_SUNPRO_VERSION +# undef HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) -#define HEDLEY_SUNPRO_VERSION \ - HEDLEY_VERSION_ENCODE( \ - (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ - (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ - (__SUNPRO_C & 0xf) * 10) +# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) -#define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C)&0xf) +# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) -#define HEDLEY_SUNPRO_VERSION \ - HEDLEY_VERSION_ENCODE( \ - (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ - (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ - (__SUNPRO_CC & 0xf) * 10) +# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) -#define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC)&0xf) +# define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) #endif #if defined(HEDLEY_SUNPRO_VERSION_CHECK) -#undef HEDLEY_SUNPRO_VERSION_CHECK +# undef HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(HEDLEY_SUNPRO_VERSION) -#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -#undef HEDLEY_EMSCRIPTEN_VERSION +# undef HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) -#define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +# define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION_CHECK) -#undef HEDLEY_EMSCRIPTEN_VERSION_CHECK +# undef HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(HEDLEY_EMSCRIPTEN_VERSION) -#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_ARM_VERSION) -#undef HEDLEY_ARM_VERSION +# undef HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) -#define HEDLEY_ARM_VERSION \ - HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) -#define HEDLEY_ARM_VERSION \ - HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +# define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) #endif #if defined(HEDLEY_ARM_VERSION_CHECK) -#undef HEDLEY_ARM_VERSION_CHECK +# undef HEDLEY_ARM_VERSION_CHECK #endif #if defined(HEDLEY_ARM_VERSION) -#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_IBM_VERSION) -#undef HEDLEY_IBM_VERSION +# undef HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) -#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) -#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) -#define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +# define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(HEDLEY_IBM_VERSION_CHECK) -#undef HEDLEY_IBM_VERSION_CHECK +# undef HEDLEY_IBM_VERSION_CHECK #endif #if defined(HEDLEY_IBM_VERSION) -#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_TI_VERSION) -#undef HEDLEY_TI_VERSION +# undef HEDLEY_TI_VERSION #endif #if defined(__TI_COMPILER_VERSION__) -#define HEDLEY_TI_VERSION \ - HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +# define HEDLEY_TI_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(HEDLEY_TI_VERSION_CHECK) -#undef HEDLEY_TI_VERSION_CHECK +# undef HEDLEY_TI_VERSION_CHECK #endif #if defined(HEDLEY_TI_VERSION) -#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_TI_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_CRAY_VERSION) -#undef HEDLEY_CRAY_VERSION +# undef HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) -#if defined(_RELEASE_PATCHLEVEL) -#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) -#else -#define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) -#endif +# if defined(_RELEASE_PATCHLEVEL) +# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) +# else +# define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +# endif #endif #if defined(HEDLEY_CRAY_VERSION_CHECK) -#undef HEDLEY_CRAY_VERSION_CHECK +# undef HEDLEY_CRAY_VERSION_CHECK #endif #if defined(HEDLEY_CRAY_VERSION) -#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_IAR_VERSION) -#undef HEDLEY_IAR_VERSION +# undef HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) -#if __VER__ > 1000 -#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) -#else -#define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) -#endif +# if __VER__ > 1000 +# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) +# else +# define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) +# endif #endif #if defined(HEDLEY_IAR_VERSION_CHECK) -#undef HEDLEY_IAR_VERSION_CHECK +# undef HEDLEY_IAR_VERSION_CHECK #endif #if defined(HEDLEY_IAR_VERSION) -#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_TINYC_VERSION) -#undef HEDLEY_TINYC_VERSION +# undef HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) -#define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +# define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) #endif #if defined(HEDLEY_TINYC_VERSION_CHECK) -#undef HEDLEY_TINYC_VERSION_CHECK +# undef HEDLEY_TINYC_VERSION_CHECK #endif #if defined(HEDLEY_TINYC_VERSION) -#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_DMC_VERSION) -#undef HEDLEY_DMC_VERSION +# undef HEDLEY_DMC_VERSION #endif #if defined(__DMC__) -#define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +# define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(HEDLEY_DMC_VERSION_CHECK) -#undef HEDLEY_DMC_VERSION_CHECK +# undef HEDLEY_DMC_VERSION_CHECK #endif #if defined(HEDLEY_DMC_VERSION) -#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_COMPCERT_VERSION) -#undef HEDLEY_COMPCERT_VERSION +# undef HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) -#define HEDLEY_COMPCERT_VERSION \ - HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +# define HEDLEY_COMPCERT_VERSION HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) #endif #if defined(HEDLEY_COMPCERT_VERSION_CHECK) -#undef HEDLEY_COMPCERT_VERSION_CHECK +# undef HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(HEDLEY_COMPCERT_VERSION) -#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_PELLES_VERSION) -#undef HEDLEY_PELLES_VERSION +# undef HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) -#define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +# define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(HEDLEY_PELLES_VERSION_CHECK) -#undef HEDLEY_PELLES_VERSION_CHECK +# undef HEDLEY_PELLES_VERSION_CHECK #endif #if defined(HEDLEY_PELLES_VERSION) -#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_GCC_VERSION) -#undef HEDLEY_GCC_VERSION +# undef HEDLEY_GCC_VERSION #endif -#if defined(HEDLEY_GNUC_VERSION) && !defined(__clang__) && !defined(HEDLEY_INTEL_VERSION) && !defined(HEDLEY_PGI_VERSION) && \ - !defined(HEDLEY_ARM_VERSION) && !defined(HEDLEY_TI_VERSION) && !defined(__COMPCERT__) -#define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION +#if \ + defined(HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(HEDLEY_INTEL_VERSION) && \ + !defined(HEDLEY_PGI_VERSION) && \ + !defined(HEDLEY_ARM_VERSION) && \ + !defined(HEDLEY_TI_VERSION) && \ + !defined(__COMPCERT__) +# define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION #endif #if defined(HEDLEY_GCC_VERSION_CHECK) -#undef HEDLEY_GCC_VERSION_CHECK +# undef HEDLEY_GCC_VERSION_CHECK #endif #if defined(HEDLEY_GCC_VERSION) -#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) +# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch)) #else -#define HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(HEDLEY_HAS_ATTRIBUTE) -#undef HEDLEY_HAS_ATTRIBUTE +# undef HEDLEY_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -#define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +# define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else -#define HEDLEY_HAS_ATTRIBUTE(attribute) (0) +# define HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_ATTRIBUTE) -#undef HEDLEY_GNUC_HAS_ATTRIBUTE +# undef HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) __has_attribute(attribute) +# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) #else -#define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_ATTRIBUTE) -#undef HEDLEY_GCC_HAS_ATTRIBUTE +# undef HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) -#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) __has_attribute(attribute) +# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) #else -#define HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_CPP_ATTRIBUTE) -#undef HEDLEY_HAS_CPP_ATTRIBUTE +# undef HEDLEY_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else -#define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +# define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) -#undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +# undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) +# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else -#define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_CPP_ATTRIBUTE) -#undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE +# undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) -#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) __has_cpp_attribute(attribute) +# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else -#define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_BUILTIN) -#undef HEDLEY_HAS_BUILTIN +# undef HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) -#define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +# define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else -#define HEDLEY_HAS_BUILTIN(builtin) (0) +# define HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(HEDLEY_GNUC_HAS_BUILTIN) -#undef HEDLEY_GNUC_HAS_BUILTIN +# undef HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) -#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) +# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else -#define HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_BUILTIN) -#undef HEDLEY_GCC_HAS_BUILTIN +# undef HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) -#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) __has_builtin(builtin) +# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else -#define HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_FEATURE) -#undef HEDLEY_HAS_FEATURE +# undef HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) -#define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +# define HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else -#define HEDLEY_HAS_FEATURE(feature) (0) +# define HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(HEDLEY_GNUC_HAS_FEATURE) -#undef HEDLEY_GNUC_HAS_FEATURE +# undef HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) -#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) +# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else -#define HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_FEATURE) -#undef HEDLEY_GCC_HAS_FEATURE +# undef HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) -#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) __has_feature(feature) +# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else -#define HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_EXTENSION) -#undef HEDLEY_HAS_EXTENSION +# undef HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) -#define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +# define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else -#define HEDLEY_HAS_EXTENSION(extension) (0) +# define HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(HEDLEY_GNUC_HAS_EXTENSION) -#undef HEDLEY_GNUC_HAS_EXTENSION +# undef HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) -#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) +# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else -#define HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_EXTENSION) -#undef HEDLEY_GCC_HAS_EXTENSION +# undef HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) -#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) __has_extension(extension) +# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else -#define HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_DECLSPEC_ATTRIBUTE) -#undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE +# undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) #else -#define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +# define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) -#undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +# undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) +# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else -#define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) -#undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +# undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) -#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) __has_declspec_attribute(attribute) +# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else -#define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_HAS_WARNING) -#undef HEDLEY_HAS_WARNING +# undef HEDLEY_HAS_WARNING #endif #if defined(__has_warning) -#define HEDLEY_HAS_WARNING(warning) __has_warning(warning) +# define HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else -#define HEDLEY_HAS_WARNING(warning) (0) +# define HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(HEDLEY_GNUC_HAS_WARNING) -#undef HEDLEY_GNUC_HAS_WARNING +# undef HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) -#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) +# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else -#define HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_GCC_HAS_WARNING) -#undef HEDLEY_GCC_HAS_WARNING +# undef HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) -#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) __has_warning(warning) +# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else -#define HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) -#endif - -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__clang__) || HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ - HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ - HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_VERSION_CHECK(6, 0, 0) || HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) || \ - HEDLEY_TINYC_VERSION_CHECK(0, 9, 17) || HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ - (HEDLEY_IBM_VERSION_CHECK(10, 1, 0) && defined(__C99_PRAGMA_OPERATOR)) -#define HEDLEY_PRAGMA(value) _Pragma(#value) -#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) -#define HEDLEY_PRAGMA(value) __pragma(value) +# define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) +# define HEDLEY_PRAGMA(value) _Pragma(#value) +#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define HEDLEY_PRAGMA(value) __pragma(value) #else -#define HEDLEY_PRAGMA(value) +# define HEDLEY_PRAGMA(value) #endif #if defined(HEDLEY_DIAGNOSTIC_PUSH) -#undef HEDLEY_DIAGNOSTIC_PUSH +# undef HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(HEDLEY_DIAGNOSTIC_POP) -#undef HEDLEY_DIAGNOSTIC_POP +# undef HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif HEDLEY_GCC_VERSION_CHECK(4, 6, 0) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) -#define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) -#define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif HEDLEY_ARM_VERSION_CHECK(5, 6, 0) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif HEDLEY_TI_VERSION_CHECK(8, 1, 0) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) -#define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") -#define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif HEDLEY_GCC_VERSION_CHECK(4,6,0) +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) +# define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif HEDLEY_ARM_VERSION_CHECK(5,6,0) +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif HEDLEY_TI_VERSION_CHECK(8,1,0) +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) +# define HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +# define HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #else -#define HEDLEY_DIAGNOSTIC_PUSH -#define HEDLEY_DIAGNOSTIC_POP +# define HEDLEY_DIAGNOSTIC_PUSH +# define HEDLEY_DIAGNOSTIC_POP #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) -#undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +# undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if HEDLEY_HAS_WARNING("-Wdeprecated-declarations") -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable : 4996)) -#elif HEDLEY_TI_VERSION_CHECK(8, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif HEDLEY_TI_VERSION_CHECK(8,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else -#define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +# define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) -#undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +# undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif HEDLEY_PGI_VERSION_CHECK(17, 10, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif HEDLEY_GCC_VERSION_CHECK(4, 3, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable : 4068)) -#elif HEDLEY_TI_VERSION_CHECK(8, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif HEDLEY_GCC_VERSION_CHECK(4,3,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif HEDLEY_TI_VERSION_CHECK(8,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") #else -#define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +# define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) -#undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +# undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if HEDLEY_HAS_WARNING("-Wcast-qual") -#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif HEDLEY_GCC_VERSION_CHECK(3, 0, 0) -#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif HEDLEY_GCC_VERSION_CHECK(3,0,0) +# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else -#define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +# define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(HEDLEY_DEPRECATED) -#undef HEDLEY_DEPRECATED +# undef HEDLEY_DEPRECATED #endif #if defined(HEDLEY_DEPRECATED_FOR) -#undef HEDLEY_DEPRECATED_FOR +# undef HEDLEY_DEPRECATED_FOR #endif #if defined(__cplusplus) && (__cplusplus >= 201402L) -#define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] -#define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] -#elif HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ - HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) || \ - HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || HEDLEY_TI_VERSION_CHECK(8, 3, 0) -#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) -#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif HEDLEY_HAS_ATTRIBUTE(deprecated) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) -#define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) -#define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " #since)) -#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_PELLES_VERSION_CHECK(6, 50, 0) -#define HEDLEY_DEPRECATED(since) _declspec(deprecated) -#define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_DEPRECATED(since) _Pragma("deprecated") -#define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +# define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] +# define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] +#elif \ + HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + HEDLEY_TI_VERSION_CHECK(8,3,0) +# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0) +# define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) +# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + HEDLEY_PELLES_VERSION_CHECK(6,50,0) +# define HEDLEY_DEPRECATED(since) _declspec(deprecated) +# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_DEPRECATED(since) _Pragma("deprecated") +# define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") #else -#define HEDLEY_DEPRECATED(since) -#define HEDLEY_DEPRECATED_FOR(since, replacement) +# define HEDLEY_DEPRECATED(since) +# define HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(HEDLEY_UNAVAILABLE) -#undef HEDLEY_UNAVAILABLE +# undef HEDLEY_UNAVAILABLE #endif -#if HEDLEY_HAS_ATTRIBUTE(warning) || HEDLEY_GCC_VERSION_CHECK(4, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#if \ + HEDLEY_HAS_ATTRIBUTE(warning) || \ + HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else -#define HEDLEY_UNAVAILABLE(available_since) +# define HEDLEY_UNAVAILABLE(available_since) #endif #if defined(HEDLEY_WARN_UNUSED_RESULT) -#undef HEDLEY_WARN_UNUSED_RESULT +# undef HEDLEY_WARN_UNUSED_RESULT #endif #if defined(__cplusplus) && (__cplusplus >= 201703L) -#define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] -#elif HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) -#define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] +#elif \ + HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ -#define HEDLEY_WARN_UNUSED_RESULT _Check_return_ +# define HEDLEY_WARN_UNUSED_RESULT _Check_return_ #else -#define HEDLEY_WARN_UNUSED_RESULT +# define HEDLEY_WARN_UNUSED_RESULT #endif #if defined(HEDLEY_SENTINEL) -#undef HEDLEY_SENTINEL -#endif -#if HEDLEY_HAS_ATTRIBUTE(sentinel) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_ARM_VERSION_CHECK(5, 4, 0) -#define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +# undef HEDLEY_SENTINEL +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(5,4,0) +# define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else -#define HEDLEY_SENTINEL(position) +# define HEDLEY_SENTINEL(position) #endif #if defined(HEDLEY_NO_RETURN) -#undef HEDLEY_NO_RETURN +# undef HEDLEY_NO_RETURN #endif -#if HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_NO_RETURN __noreturn -#elif HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#if HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_NO_RETURN __noreturn +#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -#define HEDLEY_NO_RETURN _Noreturn +# define HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) -#define HEDLEY_NO_RETURN [[noreturn]] -#elif HEDLEY_HAS_ATTRIBUTE(noreturn) || HEDLEY_GCC_VERSION_CHECK(3, 2, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ - HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(18, 0, 0) || \ - (HEDLEY_TI_VERSION_CHECK(17, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) -#define HEDLEY_NO_RETURN __declspec(noreturn) -#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) -#define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) -#define HEDLEY_NO_RETURN __attribute((noreturn)) -#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) -#define HEDLEY_NO_RETURN __declspec(noreturn) +# define HEDLEY_NO_RETURN [[noreturn]] +#elif \ + HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(18,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) +# define HEDLEY_NO_RETURN __declspec(noreturn) +#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) +# define HEDLEY_NO_RETURN __attribute((noreturn)) +#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) +# define HEDLEY_NO_RETURN __declspec(noreturn) #else -#define HEDLEY_NO_RETURN +# define HEDLEY_NO_RETURN #endif #if defined(HEDLEY_UNREACHABLE) -#undef HEDLEY_UNREACHABLE +# undef HEDLEY_UNREACHABLE #endif #if defined(HEDLEY_UNREACHABLE_RETURN) -#undef HEDLEY_UNREACHABLE_RETURN -#endif -#if (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ - HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 5) -#define HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) -#define HEDLEY_UNREACHABLE() __assume(0) -#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) -#if defined(__cplusplus) -#define HEDLEY_UNREACHABLE() std::_nassert(0) -#else -#define HEDLEY_UNREACHABLE() _nassert(0) -#endif -#define HEDLEY_UNREACHABLE_RETURN(value) return value +# undef HEDLEY_UNREACHABLE_RETURN +#endif +#if \ + (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || \ + HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_IBM_VERSION_CHECK(13,1,5) +# define HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) +# define HEDLEY_UNREACHABLE() __assume(0) +#elif HEDLEY_TI_VERSION_CHECK(6,0,0) +# if defined(__cplusplus) +# define HEDLEY_UNREACHABLE() std::_nassert(0) +# else +# define HEDLEY_UNREACHABLE() _nassert(0) +# endif +# define HEDLEY_UNREACHABLE_RETURN(value) return value #elif defined(EXIT_FAILURE) -#define HEDLEY_UNREACHABLE() abort() +# define HEDLEY_UNREACHABLE() abort() #else -#define HEDLEY_UNREACHABLE() -#define HEDLEY_UNREACHABLE_RETURN(value) return value +# define HEDLEY_UNREACHABLE() +# define HEDLEY_UNREACHABLE_RETURN(value) return value #endif #if !defined(HEDLEY_UNREACHABLE_RETURN) -#define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() +# define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE() #endif #if defined(HEDLEY_ASSUME) -#undef HEDLEY_ASSUME +# undef HEDLEY_ASSUME #endif -#if HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_ASSUME(expr) __assume(expr) +#if \ + HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_ASSUME(expr) __assume(expr) #elif HEDLEY_HAS_BUILTIN(__builtin_assume) -#define HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) -#if defined(__cplusplus) -#define HEDLEY_ASSUME(expr) std::_nassert(expr) -#else -#define HEDLEY_ASSUME(expr) _nassert(expr) -#endif -#elif (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(HEDLEY_ARM_VERSION)) || HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ - HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 5) -#define HEDLEY_ASSUME(expr) ((void)((expr) ? 1 : (__builtin_unreachable(), 1))) +# define HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif HEDLEY_TI_VERSION_CHECK(6,0,0) +# if defined(__cplusplus) +# define HEDLEY_ASSUME(expr) std::_nassert(expr) +# else +# define HEDLEY_ASSUME(expr) _nassert(expr) +# endif +#elif \ + (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(HEDLEY_ARM_VERSION)) || \ + HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_IBM_VERSION_CHECK(13,1,5) +# define HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) #else -#define HEDLEY_ASSUME(expr) ((void)(expr)) +# define HEDLEY_ASSUME(expr) ((void) (expr)) #endif + HEDLEY_DIAGNOSTIC_PUSH -#if HEDLEY_HAS_WARNING("-Wvariadic-macros") || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wvariadic-macros" -#elif defined(HEDLEY_GCC_VERSION) -#pragma GCC diagnostic ignored "-Wvariadic-macros" -#endif +#if \ + HEDLEY_HAS_WARNING("-Wvariadic-macros") || \ + HEDLEY_GCC_VERSION_CHECK(4,0,0) +# if defined(__clang__) +# pragma clang diagnostic ignored "-Wvariadic-macros" +# elif defined(HEDLEY_GCC_VERSION) +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# endif #endif #if defined(HEDLEY_NON_NULL) -#undef HEDLEY_NON_NULL -#endif -#if HEDLEY_HAS_ATTRIBUTE(nonnull) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_ARM_VERSION_CHECK(4, 1, 0) -#define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +# undef HEDLEY_NON_NULL +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) +# define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else -#define HEDLEY_NON_NULL(...) +# define HEDLEY_NON_NULL(...) #endif HEDLEY_DIAGNOSTIC_POP #if defined(HEDLEY_PRINTF_FORMAT) -#undef HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && !defined(__USE_MINGW_ANSI_STDIO) -#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && defined(__USE_MINGW_ANSI_STDIO) -#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif HEDLEY_HAS_ATTRIBUTE(format) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ - (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) -#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) __declspec(vaformat(printf, string_idx, first_to_check)) +# undef HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) +# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) +# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + HEDLEY_HAS_ATTRIBUTE(format) || \ + HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif HEDLEY_PELLES_VERSION_CHECK(6,0,0) +# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) #else -#define HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) +# define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) #endif #if defined(HEDLEY_CONSTEXPR) -#undef HEDLEY_CONSTEXPR +# undef HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) -#if __cplusplus >= 201103L -#define HEDLEY_CONSTEXPR constexpr -#endif +# if __cplusplus >= 201103L +# define HEDLEY_CONSTEXPR constexpr +# endif #endif #if !defined(HEDLEY_CONSTEXPR) -#define HEDLEY_CONSTEXPR +# define HEDLEY_CONSTEXPR #endif #if defined(HEDLEY_PREDICT) -#undef HEDLEY_PREDICT +# undef HEDLEY_PREDICT #endif #if defined(HEDLEY_LIKELY) -#undef HEDLEY_LIKELY +# undef HEDLEY_LIKELY #endif #if defined(HEDLEY_UNLIKELY) -#undef HEDLEY_UNLIKELY +# undef HEDLEY_UNLIKELY #endif #if defined(HEDLEY_UNPREDICTABLE) -#undef HEDLEY_UNPREDICTABLE +# undef HEDLEY_UNPREDICTABLE #endif #if HEDLEY_HAS_BUILTIN(__builtin_unpredictable) -#define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) -#endif -#if HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || HEDLEY_GCC_VERSION_CHECK(9, 0, 0) -#define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) -#define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) -#define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) -#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#if !defined(HEDLEY_BUILTIN_UNPREDICTABLE) -#define HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) -#endif -#elif HEDLEY_HAS_BUILTIN(__builtin_expect) || HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - (HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ - HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_TI_VERSION_CHECK(6, 1, 0) || HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) -#define HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void)(expected)), !!(expr))) -#define HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__({ \ - HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) \ - : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -#define HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__({ \ - HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) \ - : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -#define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -#define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +# define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if \ + HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) +# define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) +# define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) +# define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +# if !defined(HEDLEY_BUILTIN_UNPREDICTABLE) +# define HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +# endif +#elif \ + HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + HEDLEY_TINYC_VERSION_CHECK(0,9,27) +# define HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) +# define HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else -#define HEDLEY_PREDICT(expr, expected, probability) (((void)(expected)), !!(expr)) -#define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -#define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -#define HEDLEY_LIKELY(expr) (!!(expr)) -#define HEDLEY_UNLIKELY(expr) (!!(expr)) +# define HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define HEDLEY_LIKELY(expr) (!!(expr)) +# define HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(HEDLEY_UNPREDICTABLE) -#define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) +# define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(HEDLEY_MALLOC) -#undef HEDLEY_MALLOC -#endif -#if HEDLEY_HAS_ATTRIBUTE(malloc) || HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_MALLOC __attribute__((__malloc__)) +# undef HEDLEY_MALLOC +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(malloc) || \ + HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_MALLOC __attribute__((__malloc__)) #elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) -#define HEDLEY_MALLOC __declspec(restrict) +# define HEDLEY_MALLOC __declspec(restrict) #else -#define HEDLEY_MALLOC +# define HEDLEY_MALLOC #endif #if defined(HEDLEY_PURE) -#undef HEDLEY_PURE -#endif -#if HEDLEY_HAS_ATTRIBUTE(pure) || HEDLEY_GCC_VERSION_CHECK(2, 96, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - HEDLEY_PGI_VERSION_CHECK(17, 10, 0) -#define HEDLEY_PURE __attribute__((__pure__)) -#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) -#define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +# undef HEDLEY_PURE +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(pure) || \ + HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define HEDLEY_PURE __attribute__((__pure__)) +#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else -#define HEDLEY_PURE +# define HEDLEY_PURE #endif #if defined(HEDLEY_CONST) -#undef HEDLEY_CONST -#endif -#if HEDLEY_HAS_ATTRIBUTE(const) || HEDLEY_GCC_VERSION_CHECK(2, 5, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - HEDLEY_PGI_VERSION_CHECK(17, 10, 0) -#define HEDLEY_CONST __attribute__((__const__)) +# undef HEDLEY_CONST +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(const) || \ + HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + HEDLEY_PGI_VERSION_CHECK(17,10,0) +# define HEDLEY_CONST __attribute__((__const__)) #else -#define HEDLEY_CONST HEDLEY_PURE +# define HEDLEY_CONST HEDLEY_PURE #endif #if defined(HEDLEY_RESTRICT) -#undef HEDLEY_RESTRICT +# undef HEDLEY_RESTRICT #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) -#define HEDLEY_RESTRICT restrict -#elif HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) || \ - HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || defined(__clang__) -#define HEDLEY_RESTRICT __restrict -#elif HEDLEY_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) -#define HEDLEY_RESTRICT _Restrict +# define HEDLEY_RESTRICT restrict +#elif \ + HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) +# define HEDLEY_RESTRICT __restrict +#elif HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) +# define HEDLEY_RESTRICT _Restrict #else -#define HEDLEY_RESTRICT +# define HEDLEY_RESTRICT #endif #if defined(HEDLEY_INLINE) -#undef HEDLEY_INLINE -#endif -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) -#define HEDLEY_INLINE inline -#elif defined(HEDLEY_GCC_VERSION) || HEDLEY_ARM_VERSION_CHECK(6, 2, 0) -#define HEDLEY_INLINE __inline__ -#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_TI_VERSION_CHECK(8, 0, 0) -#define HEDLEY_INLINE __inline +# undef HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) +# define HEDLEY_INLINE inline +#elif \ + defined(HEDLEY_GCC_VERSION) || \ + HEDLEY_ARM_VERSION_CHECK(6,2,0) +# define HEDLEY_INLINE __inline__ +#elif \ + HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) +# define HEDLEY_INLINE __inline #else -#define HEDLEY_INLINE +# define HEDLEY_INLINE #endif #if defined(HEDLEY_ALWAYS_INLINE) -#undef HEDLEY_ALWAYS_INLINE -#endif -#if HEDLEY_HAS_ATTRIBUTE(always_inline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE -#elif HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) -#define HEDLEY_ALWAYS_INLINE __forceinline -#elif HEDLEY_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus) -#define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +# undef HEDLEY_ALWAYS_INLINE +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE +#elif HEDLEY_MSVC_VERSION_CHECK(12,0,0) +# define HEDLEY_ALWAYS_INLINE __forceinline +#elif HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) +# define HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else -#define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE +# define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE #endif #if defined(HEDLEY_NEVER_INLINE) -#undef HEDLEY_NEVER_INLINE -#endif -#if HEDLEY_HAS_ATTRIBUTE(noinline) || HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) -#define HEDLEY_NEVER_INLINE __declspec(noinline) -#elif HEDLEY_PGI_VERSION_CHECK(10, 2, 0) -#define HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) -#define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) -#define HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) -#define HEDLEY_NEVER_INLINE __declspec(noinline) +# undef HEDLEY_NEVER_INLINE +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(noinline) || \ + HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0) +# define HEDLEY_NEVER_INLINE __declspec(noinline) +#elif HEDLEY_PGI_VERSION_CHECK(10,2,0) +# define HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) +# define HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0) +# define HEDLEY_NEVER_INLINE __declspec(noinline) #else -#define HEDLEY_NEVER_INLINE +# define HEDLEY_NEVER_INLINE #endif #if defined(HEDLEY_PRIVATE) -#undef HEDLEY_PRIVATE +# undef HEDLEY_PRIVATE #endif #if defined(HEDLEY_PUBLIC) -#undef HEDLEY_PUBLIC +# undef HEDLEY_PUBLIC #endif #if defined(HEDLEY_IMPORT) -#undef HEDLEY_IMPORT +# undef HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) -#define HEDLEY_PRIVATE -#define HEDLEY_PUBLIC __declspec(dllexport) -#define HEDLEY_IMPORT __declspec(dllimport) -#else -#if HEDLEY_HAS_ATTRIBUTE(visibility) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ - HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ - (HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) -#define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -#define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# define HEDLEY_PRIVATE +# define HEDLEY_PUBLIC __declspec(dllexport) +# define HEDLEY_IMPORT __declspec(dllimport) #else -#define HEDLEY_PRIVATE -#define HEDLEY_PUBLIC -#endif -#define HEDLEY_IMPORT extern +# if \ + HEDLEY_HAS_ATTRIBUTE(visibility) || \ + HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +# define HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define HEDLEY_PRIVATE +# define HEDLEY_PUBLIC +# endif +# define HEDLEY_IMPORT extern #endif #if defined(HEDLEY_NO_THROW) -#undef HEDLEY_NO_THROW -#endif -#if HEDLEY_HAS_ATTRIBUTE(nothrow) || HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) -#define HEDLEY_NO_THROW __declspec(nothrow) +# undef HEDLEY_NO_THROW +#endif +#if \ + HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) +# define HEDLEY_NO_THROW __declspec(nothrow) #else -#define HEDLEY_NO_THROW +# define HEDLEY_NO_THROW #endif #if defined(HEDLEY_FALL_THROUGH) -#undef HEDLEY_FALL_THROUGH -#endif -#if defined(__cplusplus) && (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) && !defined(HEDLEY_PGI_VERSION) -#if (__cplusplus >= 201703L) || ((__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) -#define HEDLEY_FALL_THROUGH [[fallthrough]] -#elif (__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) -#define HEDLEY_FALL_THROUGH [[clang::fallthrough]] -#elif (__cplusplus >= 201103L) && HEDLEY_GCC_VERSION_CHECK(7, 0, 0) -#define HEDLEY_FALL_THROUGH [[gnu::fallthrough]] -#endif +# undef HEDLEY_FALL_THROUGH +#endif +#if \ + defined(__cplusplus) && \ + (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + !defined(HEDLEY_PGI_VERSION) +# if \ + (__cplusplus >= 201703L) || \ + ((__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) +# define HEDLEY_FALL_THROUGH [[fallthrough]] +# elif (__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) +# define HEDLEY_FALL_THROUGH [[clang::fallthrough]] +# elif (__cplusplus >= 201103L) && HEDLEY_GCC_VERSION_CHECK(7,0,0) +# define HEDLEY_FALL_THROUGH [[gnu::fallthrough]] +# endif #endif #if !defined(HEDLEY_FALL_THROUGH) -#if HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough, 7, 0, 0) && !defined(HEDLEY_PGI_VERSION) -#define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif defined(__fallthrough) /* SAL */ -#define HEDLEY_FALL_THROUGH __fallthrough -#else -#define HEDLEY_FALL_THROUGH -#endif +# if HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(HEDLEY_PGI_VERSION) +# define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +# elif defined(__fallthrough) /* SAL */ +# define HEDLEY_FALL_THROUGH __fallthrough +# else +# define HEDLEY_FALL_THROUGH +# endif #endif #if defined(HEDLEY_RETURNS_NON_NULL) -#undef HEDLEY_RETURNS_NON_NULL +# undef HEDLEY_RETURNS_NON_NULL #endif -#if HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || HEDLEY_GCC_VERSION_CHECK(4, 9, 0) -#define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#if \ + HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + HEDLEY_GCC_VERSION_CHECK(4,9,0) +# define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ -#define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +# define HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else -#define HEDLEY_RETURNS_NON_NULL +# define HEDLEY_RETURNS_NON_NULL #endif #if defined(HEDLEY_ARRAY_PARAM) -#undef HEDLEY_ARRAY_PARAM -#endif -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ - !defined(HEDLEY_PGI_VERSION) && !defined(HEDLEY_TINYC_VERSION) -#define HEDLEY_ARRAY_PARAM(name) (name) +# undef HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(HEDLEY_PGI_VERSION) && \ + !defined(HEDLEY_TINYC_VERSION) +# define HEDLEY_ARRAY_PARAM(name) (name) #else -#define HEDLEY_ARRAY_PARAM(name) +# define HEDLEY_ARRAY_PARAM(name) #endif #if defined(HEDLEY_IS_CONSTANT) -#undef HEDLEY_IS_CONSTANT +# undef HEDLEY_IS_CONSTANT #endif #if defined(HEDLEY_REQUIRE_CONSTEXPR) -#undef HEDLEY_REQUIRE_CONSTEXPR +# undef HEDLEY_REQUIRE_CONSTEXPR #endif /* Note the double-underscore. For internal use only; no API * guarantees! */ #if defined(HEDLEY__IS_CONSTEXPR) -#undef HEDLEY__IS_CONSTEXPR +# undef HEDLEY__IS_CONSTEXPR #endif -#if HEDLEY_HAS_BUILTIN(__builtin_constant_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_TINYC_VERSION_CHECK(0, 9, 19) || HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ - HEDLEY_TI_VERSION_CHECK(6, 1, 0) || HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) || HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) -#define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#if \ + HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \ + HEDLEY_CRAY_VERSION_CHECK(8,1,0) +# define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) -#if HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ - HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || \ - HEDLEY_TINYC_VERSION_CHECK(0, 9, 24) -#if defined(__INTPTR_TYPE__) -#define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*)((__INTPTR_TYPE__)((expr)*0)) : (int*)0)), int*) -#else -#include -#define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*)((intptr_t)((expr)*0)) : (int*)0)), int*) -#endif -#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && !defined(HEDLEY_PGI_VERSION)) || \ - HEDLEY_HAS_EXTENSION(c_generic_selections) || HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) || \ - HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || HEDLEY_ARM_VERSION_CHECK(5, 3, 0) -#if defined(__INTPTR_TYPE__) -#define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*)((__INTPTR_TYPE__)((expr)*0)) : (int*)0), int* : 1, void* : 0) -#else -#include -#define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*)((intptr_t)*0) : (int*)0), int* : 1, void* : 0) -#endif -#elif defined(HEDLEY_GCC_VERSION) || defined(HEDLEY_INTEL_VERSION) || defined(HEDLEY_TINYC_VERSION) || defined(HEDLEY_TI_VERSION) || \ - defined(__clang__) -#define HEDLEY__IS_CONSTEXPR(expr) (sizeof(void) != sizeof(*(1 ? ((void*)((expr)*0L)) : ((struct { char v[sizeof(void) * 2]; }*)1)))) -#endif +# if \ + HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + HEDLEY_TINYC_VERSION_CHECK(0,9,24) +# if defined(__INTPTR_TYPE__) +# define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +# else +# include +# define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +# endif +# elif \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && !defined(HEDLEY_PGI_VERSION)) || \ + HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + HEDLEY_ARM_VERSION_CHECK(5,3,0) +# if defined(__INTPTR_TYPE__) +# define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +# else +# include +# define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +# endif +# elif \ + defined(HEDLEY_GCC_VERSION) || \ + defined(HEDLEY_INTEL_VERSION) || \ + defined(HEDLEY_TINYC_VERSION) || \ + defined(HEDLEY_TI_VERSION) || \ + defined(__clang__) +# define HEDLEY__IS_CONSTEXPR(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ + ((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif #endif #if defined(HEDLEY__IS_CONSTEXPR) -#if !defined(HEDLEY_IS_CONSTANT) -#define HEDLEY_IS_CONSTANT(expr) HEDLEY__IS_CONSTEXPR(expr) -#endif -#define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) +# if !defined(HEDLEY_IS_CONSTANT) +# define HEDLEY_IS_CONSTANT(expr) HEDLEY__IS_CONSTEXPR(expr) +# endif +# define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) #else -#if !defined(HEDLEY_IS_CONSTANT) -#define HEDLEY_IS_CONSTANT(expr) (0) -#endif -#define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +# if !defined(HEDLEY_IS_CONSTANT) +# define HEDLEY_IS_CONSTANT(expr) (0) +# endif +# define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(HEDLEY_BEGIN_C_DECLS) -#undef HEDLEY_BEGIN_C_DECLS +# undef HEDLEY_BEGIN_C_DECLS #endif #if defined(HEDLEY_END_C_DECLS) -#undef HEDLEY_END_C_DECLS +# undef HEDLEY_END_C_DECLS #endif #if defined(HEDLEY_C_DECL) -#undef HEDLEY_C_DECL +# undef HEDLEY_C_DECL #endif #if defined(__cplusplus) -#define HEDLEY_BEGIN_C_DECLS extern "C" { -#define HEDLEY_END_C_DECLS } -#define HEDLEY_C_DECL extern "C" +# define HEDLEY_BEGIN_C_DECLS extern "C" { +# define HEDLEY_END_C_DECLS } +# define HEDLEY_C_DECL extern "C" #else -#define HEDLEY_BEGIN_C_DECLS -#define HEDLEY_END_C_DECLS -#define HEDLEY_C_DECL +# define HEDLEY_BEGIN_C_DECLS +# define HEDLEY_END_C_DECLS +# define HEDLEY_C_DECL #endif #if defined(HEDLEY_STATIC_ASSERT) -#undef HEDLEY_STATIC_ASSERT -#endif -#if !defined(__cplusplus) && \ - ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || HEDLEY_HAS_FEATURE(c_static_assert) || \ - HEDLEY_GCC_VERSION_CHECK(6, 0, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || defined(_Static_assert)) -#define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif (defined(__cplusplus) && (__cplusplus >= 201703L)) || HEDLEY_MSVC_VERSION_CHECK(16, 0, 0) || \ - (defined(__cplusplus) && HEDLEY_TI_VERSION_CHECK(8, 3, 0)) -#define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) +# undef HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + HEDLEY_HAS_FEATURE(c_static_assert) || \ + HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201703L)) || \ + HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + (defined(__cplusplus) && HEDLEY_TI_VERSION_CHECK(8,3,0)) +# define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) #elif defined(__cplusplus) && (__cplusplus >= 201103L) -#define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) +# define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) #else -#define HEDLEY_STATIC_ASSERT(expr, message) +# define HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(HEDLEY_CONST_CAST) -#undef HEDLEY_CONST_CAST +# undef HEDLEY_CONST_CAST #endif #if defined(__cplusplus) -#define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif HEDLEY_HAS_WARNING("-Wcast-qual") || HEDLEY_GCC_VERSION_CHECK(4, 6, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_CONST_CAST(T, expr) \ - (__extension__({ \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL((T)(expr)); \ - HEDLEY_DIAGNOSTIC_POP \ +# define HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + HEDLEY_HAS_WARNING("-Wcast-qual") || \ + HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + HEDLEY_DIAGNOSTIC_POP \ })) #else -#define HEDLEY_CONST_CAST(T, expr) ((T)(expr)) +# define HEDLEY_CONST_CAST(T, expr) ((T) (expr)) #endif #if defined(HEDLEY_REINTERPRET_CAST) -#undef HEDLEY_REINTERPRET_CAST +# undef HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) -#define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +# define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else -#define HEDLEY_REINTERPRET_CAST(T, expr) (*((T*)&(expr))) +# define HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) #endif #if defined(HEDLEY_STATIC_CAST) -#undef HEDLEY_STATIC_CAST +# undef HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) -#define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +# define HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else -#define HEDLEY_STATIC_CAST(T, expr) ((T)(expr)) +# define HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) #endif #if defined(HEDLEY_CPP_CAST) -#undef HEDLEY_CPP_CAST +# undef HEDLEY_CPP_CAST #endif #if defined(__cplusplus) -#define HEDLEY_CPP_CAST(T, expr) static_cast(expr) +# define HEDLEY_CPP_CAST(T, expr) static_cast(expr) #else -#define HEDLEY_CPP_CAST(T, expr) (expr) +# define HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(HEDLEY_MESSAGE) -#undef HEDLEY_MESSAGE +# undef HEDLEY_MESSAGE #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -#define HEDLEY_MESSAGE(msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - HEDLEY_PRAGMA(message msg) \ - HEDLEY_DIAGNOSTIC_POP -#elif HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) -#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) -#elif HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) -#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) -#elif HEDLEY_IAR_VERSION_CHECK(8, 0, 0) -#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) -#elif HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) -#define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +# define HEDLEY_MESSAGE(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(message msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif \ + HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg) +#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg) +#elif HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) +#elif HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg)) #else -#define HEDLEY_MESSAGE(msg) +# define HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_WARNING) -#undef HEDLEY_WARNING +# undef HEDLEY_WARNING #endif #if HEDLEY_HAS_WARNING("-Wunknown-pragmas") -#define HEDLEY_WARNING(msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - HEDLEY_PRAGMA(clang warning msg) \ - HEDLEY_DIAGNOSTIC_POP -#elif HEDLEY_GCC_VERSION_CHECK(4, 8, 0) || HEDLEY_PGI_VERSION_CHECK(18, 4, 0) -#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) -#elif HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) -#define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) +# define HEDLEY_WARNING(msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + HEDLEY_PRAGMA(clang warning msg) \ + HEDLEY_DIAGNOSTIC_POP +#elif \ + HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + HEDLEY_PGI_VERSION_CHECK(18,4,0) +# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg) +#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg)) #else -#define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) +# define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg) #endif #if defined(HEDLEY_REQUIRE_MSG) -#undef HEDLEY_REQUIRE_MSG +# undef HEDLEY_REQUIRE_MSG #endif #if HEDLEY_HAS_ATTRIBUTE(diagnose_if) -#if HEDLEY_HAS_WARNING("-Wgcc-compat") -#define HEDLEY_REQUIRE_MSG(expr, msg) \ - HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") __attribute__((__diagnose_if__(!(expr), msg, "error"))) HEDLEY_DIAGNOSTIC_POP -#else -#define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) -#endif +# if HEDLEY_HAS_WARNING("-Wgcc-compat") +# define HEDLEY_REQUIRE_MSG(expr, msg) \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((__diagnose_if__(!(expr), msg, "error"))) \ + HEDLEY_DIAGNOSTIC_POP +# else +# define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) +# endif #else -#define HEDLEY_REQUIRE_MSG(expr, msg) +# define HEDLEY_REQUIRE_MSG(expr, msg) #endif #if defined(HEDLEY_REQUIRE) -#undef HEDLEY_REQUIRE +# undef HEDLEY_REQUIRE #endif #define HEDLEY_REQUIRE(expr) HEDLEY_REQUIRE_MSG(expr, #expr) #if defined(HEDLEY_FLAGS) -#undef HEDLEY_FLAGS +# undef HEDLEY_FLAGS #endif #if HEDLEY_HAS_ATTRIBUTE(flag_enum) -#define HEDLEY_FLAGS __attribute__((__flag_enum__)) +# define HEDLEY_FLAGS __attribute__((__flag_enum__)) #endif #if defined(HEDLEY_FLAGS_CAST) -#undef HEDLEY_FLAGS_CAST -#endif -#if HEDLEY_INTEL_VERSION_CHECK(19, 0, 0) -#define HEDLEY_FLAGS_CAST(T, expr) \ - (__extension__({ \ - HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)")((T)(expr)); \ - HEDLEY_DIAGNOSTIC_POP \ +# undef HEDLEY_FLAGS_CAST +#endif +#if HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + HEDLEY_DIAGNOSTIC_POP \ })) #else -#define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) +# define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr) #endif /* Remaining macros are deprecated. */ #if defined(HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) -#undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +# undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) -#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) (0) +# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) #else -#define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) HEDLEY_GCC_VERSION_CHECK(major, minor, patch) +# define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(HEDLEY_CLANG_HAS_ATTRIBUTE) -#undef HEDLEY_CLANG_HAS_ATTRIBUTE +# undef HEDLEY_CLANG_HAS_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) -#undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +# undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_BUILTIN) -#undef HEDLEY_CLANG_HAS_BUILTIN +# undef HEDLEY_CLANG_HAS_BUILTIN #endif #define HEDLEY_CLANG_HAS_BUILTIN(builtin) HEDLEY_HAS_BUILTIN(builtin) #if defined(HEDLEY_CLANG_HAS_FEATURE) -#undef HEDLEY_CLANG_HAS_FEATURE +# undef HEDLEY_CLANG_HAS_FEATURE #endif #define HEDLEY_CLANG_HAS_FEATURE(feature) HEDLEY_HAS_FEATURE(feature) #if defined(HEDLEY_CLANG_HAS_EXTENSION) -#undef HEDLEY_CLANG_HAS_EXTENSION +# undef HEDLEY_CLANG_HAS_EXTENSION #endif #define HEDLEY_CLANG_HAS_EXTENSION(extension) HEDLEY_HAS_EXTENSION(extension) #if defined(HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) -#undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +# undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif #define HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(HEDLEY_CLANG_HAS_WARNING) -#undef HEDLEY_CLANG_HAS_WARNING +# undef HEDLEY_CLANG_HAS_WARNING #endif #define HEDLEY_CLANG_HAS_WARNING(warning) HEDLEY_HAS_WARNING(warning) #endif /* !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < X) */ -namespace csv -{ + +namespace csv { #ifdef _MSC_VER #pragma region Compatibility Macros #endif @@ -4695,59 +4699,59 @@ namespace csv #define CSV_HAS_CXX17 #endif -#if CMAKE_CXX_STANDARD >= 14 || __cplusplus >= 201402L +#if CMAKE_CXX_STANDARD >= 14 || __cplusplus >= 201402L #define CSV_HAS_CXX14 #endif #ifdef CSV_HAS_CXX17 #include - /** @typedef string_view - * The string_view class used by this library. - */ + /** @typedef string_view + * The string_view class used by this library. + */ using string_view = std::string_view; #else - /** @typedef string_view - * The string_view class used by this library. - */ + /** @typedef string_view + * The string_view class used by this library. + */ using string_view = nonstd::string_view; #endif #ifdef CSV_HAS_CXX17 -#define IF_CONSTEXPR if constexpr -#define CONSTEXPR_VALUE constexpr + #define IF_CONSTEXPR if constexpr + #define CONSTEXPR_VALUE constexpr -#define CONSTEXPR_17 constexpr + #define CONSTEXPR_17 constexpr #else -#define IF_CONSTEXPR if -#define CONSTEXPR_VALUE const + #define IF_CONSTEXPR if + #define CONSTEXPR_VALUE const -#define CONSTEXPR_17 inline + #define CONSTEXPR_17 inline #endif #ifdef CSV_HAS_CXX14 template using enable_if_t = std::enable_if_t; -#define CONSTEXPR_14 constexpr -#define CONSTEXPR_VALUE_14 constexpr + #define CONSTEXPR_14 constexpr + #define CONSTEXPR_VALUE_14 constexpr #else template using enable_if_t = typename std::enable_if::type; -#define CONSTEXPR_14 inline -#define CONSTEXPR_VALUE_14 const + #define CONSTEXPR_14 inline + #define CONSTEXPR_VALUE_14 const #endif // Resolves g++ bug with regard to constexpr methods // See: https://stackoverflow.com/questions/36489369/constexpr-non-static-member-function-with-non-constexpr-constructor-gcc-clang-d #if defined __GNUC__ && !defined __clang__ -#if (__GNUC__ >= 7 && __GNUC_MINOR__ >= 2) || (__GNUC__ >= 8) -#define CONSTEXPR constexpr -#endif -#else -#ifdef CSV_HAS_CXX17 -#define CONSTEXPR constexpr -#endif + #if (__GNUC__ >= 7 &&__GNUC_MINOR__ >= 2) || (__GNUC__ >= 8) + #define CONSTEXPR constexpr + #endif + #else + #ifdef CSV_HAS_CXX17 + #define CONSTEXPR constexpr + #endif #endif #ifndef CONSTEXPR @@ -4758,8 +4762,7 @@ namespace csv #pragma endregion #endif - namespace internals - { + namespace internals { // PAGE_SIZE macro could be already defined by the host system. #if defined(PAGE_SIZE) #undef PAGE_SIZE @@ -4767,15 +4770,14 @@ namespace csv // Get operating system specific details #if defined(_WIN32) - inline int getpagesize() - { + inline int getpagesize() { _SYSTEM_INFO sys_info = {}; GetSystemInfo(&sys_info); return std::max(sys_info.dwPageSize, sys_info.dwAllocationGranularity); } const int PAGE_SIZE = getpagesize(); -#elif defined(__linux__) +#elif defined(__linux__) const int PAGE_SIZE = getpagesize(); #else /** Size of a memory page in bytes. Used by @@ -4790,8 +4792,7 @@ namespace csv constexpr size_t ITERATION_CHUNK_SIZE = 10000000; // 10MB template - inline bool is_equal(T a, T b, T epsilon = 0.001) - { + inline bool is_equal(T a, T b, T epsilon = 0.001) { /** Returns true if two floating point values are about the same */ static_assert(std::is_floating_point::value, "T must be a floating point type."); return std::abs(a - b) < epsilon; @@ -4803,19 +4804,17 @@ namespace csv * * @see quote_escape_flag */ - enum class ParseFlags - { + enum class ParseFlags { QUOTE_ESCAPE_QUOTE = 0, /**< A quote inside or terminating a quote_escaped field */ - QUOTE = 2 | 1, /**< Characters which may signify a quote escape */ - NOT_SPECIAL = 4, /**< Characters with no special meaning or escaped delimiters and newlines */ - DELIMITER = 4 | 2, /**< Characters which signify a new field */ - NEWLINE = 4 | 2 | 1 /**< Characters which signify a new row */ + QUOTE = 2 | 1, /**< Characters which may signify a quote escape */ + NOT_SPECIAL = 4, /**< Characters with no special meaning or escaped delimiters and newlines */ + DELIMITER = 4 | 2, /**< Characters which signify a new field */ + NEWLINE = 4 | 2 | 1 /**< Characters which signify a new row */ }; /** Transform the ParseFlags given the context of whether or not the current * field is quote escaped */ - constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept - { + constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept { return (ParseFlags)((int)flag & ~((int)ParseFlags::QUOTE * quote_escape)); } @@ -4843,32 +4842,29 @@ namespace csv /** An array which maps ASCII chars to a flag indicating if it is whitespace */ using WhitespaceMap = std::array; - } // namespace internals + } /** Integer indicating a requested column wasn't found. */ constexpr int CSV_NOT_FOUND = -1; -} // namespace csv +} -namespace csv -{ - namespace internals - { + +namespace csv { + namespace internals { struct ColNames; using ColNamesPtr = std::shared_ptr; /** @struct ColNames - * A data structure for handling column name information. - * - * These are created by CSVReader and passed (via smart pointer) - * to CSVRow objects it creates, thus - * allowing for indexing by column name. - */ - struct ColNames - { + * A data structure for handling column name information. + * + * These are created by CSVReader and passed (via smart pointer) + * to CSVRow objects it creates, thus + * allowing for indexing by column name. + */ + struct ColNames { public: ColNames() = default; - ColNames(const std::vector& names) - { + ColNames(const std::vector& names) { set_col_names(names); } @@ -4876,18 +4872,15 @@ namespace csv void set_col_names(const std::vector&); int index_of(csv::string_view) const; - bool empty() const noexcept - { - return this->col_names.empty(); - } + bool empty() const noexcept { return this->col_names.empty(); } size_t size() const noexcept; private: std::vector col_names; std::unordered_map col_pos; }; - } // namespace internals -} // namespace csv + } +} /** @file * Defines an object used to store CSV format settings */ @@ -4897,35 +4890,31 @@ namespace csv #include #include -namespace csv -{ - namespace internals - { + +namespace csv { + namespace internals { class IBasicCSVParser; } class CSVReader; /** Determines how to handle rows that are shorter or longer than the majority */ - enum class VariableColumnPolicy - { + enum class VariableColumnPolicy { THROW = -1, IGNORE_ROW = 0, - KEEP = 1 + KEEP = 1 }; /** Stores the inferred format of a CSV file. */ - struct CSVGuessResult - { + struct CSVGuessResult { char delim; int header_row; }; /** Stores information about how to parse a CSV file. - * Can be used to construct a csv::CSVReader. + * Can be used to construct a csv::CSVReader. */ - class CSVFormat - { + class CSVFormat { public: /** Settings for parsing a RFC 4180 CSV file */ CSVFormat() = default; @@ -4937,18 +4926,18 @@ namespace csv CSVFormat& delimiter(char delim); /** Sets a list of potential delimiters - * + * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] delim An array of possible delimiters to try parsing the CSV with */ - CSVFormat& delimiter(const std::vector& delim); + CSVFormat& delimiter(const std::vector & delim); /** Sets the whitespace characters to be trimmed * * @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap * @param[in] ws An array of whitespace characters that should be trimmed */ - CSVFormat& trim(const std::vector& ws); + CSVFormat& trim(const std::vector & ws); /** Sets the quote character * @@ -4973,88 +4962,64 @@ namespace csv * @note Equivalent to `header_row(-1)` * */ - CSVFormat& no_header() - { + CSVFormat& no_header() { this->header_row(-1); return *this; } /** Turn quoting on or off */ - CSVFormat& quote(bool use_quote) - { + CSVFormat& quote(bool use_quote) { this->no_quote = !use_quote; return *this; } /** Tells the parser how to handle columns of a different length than the others */ - CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) - { + CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) { this->variable_column_policy = policy; return *this; } /** Tells the parser how to handle columns of a different length than the others */ - CONSTEXPR_14 CSVFormat& variable_columns(bool policy) - { + CONSTEXPR_14 CSVFormat& variable_columns(bool policy) { this->variable_column_policy = (VariableColumnPolicy)policy; return *this; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS - char get_delim() const - { + #ifndef DOXYGEN_SHOULD_SKIP_THIS + char get_delim() const { // This error should never be received by end users. - if (this->possible_delimiters.size() > 1) - { + if (this->possible_delimiters.size() > 1) { throw std::runtime_error("There is more than one possible delimiter."); } return this->possible_delimiters.at(0); } - CONSTEXPR bool is_quoting_enabled() const - { - return !this->no_quote; - } - CONSTEXPR char get_quote_char() const - { - return this->quote_char; - } - CONSTEXPR int get_header() const - { - return this->header; - } - std::vector get_possible_delims() const - { - return this->possible_delimiters; - } - std::vector get_trim_chars() const - { - return this->trim_chars; - } - CONSTEXPR VariableColumnPolicy get_variable_column_policy() const - { - return this->variable_column_policy; - } -#endif - + CONSTEXPR bool is_quoting_enabled() const { return !this->no_quote; } + CONSTEXPR char get_quote_char() const { return this->quote_char; } + CONSTEXPR int get_header() const { return this->header; } + std::vector get_possible_delims() const { return this->possible_delimiters; } + std::vector get_trim_chars() const { return this->trim_chars; } + CONSTEXPR VariableColumnPolicy get_variable_column_policy() const { return this->variable_column_policy; } + #endif + /** CSVFormat for guessing the delimiter */ - CSV_INLINE static CSVFormat guess_csv() - { + CSV_INLINE static CSVFormat guess_csv() { CSVFormat format; - format.delimiter({ ',', '|', '\t', ';', '^' }).quote('"').header_row(0); + format.delimiter({ ',', '|', '\t', ';', '^' }) + .quote('"') + .header_row(0); return format; } - bool guess_delim() - { + bool guess_delim() { return this->possible_delimiters.size() > 1; } friend CSVReader; friend internals::IBasicCSVParser; - + private: /**< Throws an error if delimiters and trim characters overlap */ void assert_no_char_overlap(); @@ -5080,67 +5045,65 @@ namespace csv /**< Allow variable length columns? */ VariableColumnPolicy variable_column_policy = VariableColumnPolicy::IGNORE_ROW; }; -} // namespace csv +} /** @file * Defines the data type used for storing information about a CSV row */ #include #include -#include // For CSVField #include // For CSVField -#include -#include +#include // For CSVField #include #include +#include +#include #include /** @file * @brief Implements data type parsing functionality */ -#include -#include #include +#include #include +#include -namespace csv -{ + +namespace csv { /** Enumerates the different CSV field types that are * recognized by this library * * @note Overflowing integers will be stored and classified as doubles. * @note Unlike previous releases, integer enums here are platform agnostic. */ - enum class DataType - { + enum class DataType { UNKNOWN = -1, - CSV_NULL, /**< Empty string */ + CSV_NULL, /**< Empty string */ CSV_STRING, /**< Non-numeric string */ - CSV_INT8, /**< 8-bit integer */ - CSV_INT16, /**< 16-bit integer (short on MSVC/GCC) */ - CSV_INT32, /**< 32-bit integer (int on MSVC/GCC) */ - CSV_INT64, /**< 64-bit integer (long long on MSVC/GCC) */ - CSV_DOUBLE /**< Floating point value */ + CSV_INT8, /**< 8-bit integer */ + CSV_INT16, /**< 16-bit integer (short on MSVC/GCC) */ + CSV_INT32, /**< 32-bit integer (int on MSVC/GCC) */ + CSV_INT64, /**< 64-bit integer (long long on MSVC/GCC) */ + CSV_DOUBLE /**< Floating point value */ }; static_assert(DataType::CSV_STRING < DataType::CSV_INT8, "String type should come before numeric types."); static_assert(DataType::CSV_INT8 < DataType::CSV_INT64, "Smaller integer types should come before larger integer types."); static_assert(DataType::CSV_INT64 < DataType::CSV_DOUBLE, "Integer types should come before floating point value types."); - namespace internals - { + namespace internals { /** Compute 10 to the power of n */ template - HEDLEY_CONST CONSTEXPR_14 long double pow10(const T& n) noexcept - { - long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; + HEDLEY_CONST CONSTEXPR_14 + long double pow10(const T& n) noexcept { + long double multiplicand = n > 0 ? 10 : 0.1, + ret = 1; // Make all numbers positive T iterations = n > 0 ? n : -n; - - for (T i = 0; i < iterations; i++) - { + + for (T i = 0; i < iterations; i++) { ret *= multiplicand; } @@ -5149,12 +5112,12 @@ namespace csv /** Compute 10 to the power of n */ template<> - HEDLEY_CONST CONSTEXPR_14 long double pow10(const unsigned& n) noexcept - { - long double multiplicand = n > 0 ? 10 : 0.1, ret = 1; + HEDLEY_CONST CONSTEXPR_14 + long double pow10(const unsigned& n) noexcept { + long double multiplicand = n > 0 ? 10 : 0.1, + ret = 1; - for (unsigned i = 0; i < n; i++) - { + for (unsigned i = 0; i < n; i++) { ret *= multiplicand; } @@ -5164,47 +5127,28 @@ namespace csv #ifndef DOXYGEN_SHOULD_SKIP_THIS /** Private site-indexed array mapping byte sizes to an integer size enum */ constexpr DataType int_type_arr[8] = { - DataType::CSV_INT8, // 1 + DataType::CSV_INT8, // 1 DataType::CSV_INT16, // 2 DataType::UNKNOWN, DataType::CSV_INT32, // 4 - DataType::UNKNOWN, DataType::UNKNOWN, DataType::UNKNOWN, - DataType::CSV_INT64 // 8 + DataType::UNKNOWN, + DataType::UNKNOWN, + DataType::UNKNOWN, + DataType::CSV_INT64 // 8 }; template - inline DataType type_num() - { + inline DataType type_num() { static_assert(std::is_integral::value, "T should be an integral type."); static_assert(sizeof(T) <= 8, "Byte size must be no greater than 8."); return int_type_arr[sizeof(T) - 1]; } - template<> - inline DataType type_num() - { - return DataType::CSV_DOUBLE; - } - template<> - inline DataType type_num() - { - return DataType::CSV_DOUBLE; - } - template<> - inline DataType type_num() - { - return DataType::CSV_DOUBLE; - } - template<> - inline DataType type_num() - { - return DataType::CSV_NULL; - } - template<> - inline DataType type_num() - { - return DataType::CSV_STRING; - } + template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } + template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } + template<> inline DataType type_num() { return DataType::CSV_DOUBLE; } + template<> inline DataType type_num() { return DataType::CSV_NULL; } + template<> inline DataType type_num() { return DataType::CSV_STRING; } CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr); #endif @@ -5216,32 +5160,27 @@ namespace csv * byte sizes */ template - CONSTEXPR_14 long double get_int_max() - { - static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); + CONSTEXPR_14 long double get_int_max() { + static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, + "Bytes must be a power of 2 below 8."); - IF_CONSTEXPR(sizeof(signed char) == Bytes) - { + IF_CONSTEXPR (sizeof(signed char) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(short) == Bytes) - { + IF_CONSTEXPR (sizeof(short) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(int) == Bytes) - { + IF_CONSTEXPR (sizeof(int) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(long int) == Bytes) - { + IF_CONSTEXPR (sizeof(long int) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(long long int) == Bytes) - { + IF_CONSTEXPR (sizeof(long long int) == Bytes) { return (long double)std::numeric_limits::max(); } @@ -5252,32 +5191,27 @@ namespace csv * an unsigned integer of that size */ template - CONSTEXPR_14 long double get_uint_max() - { - static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, "Bytes must be a power of 2 below 8."); + CONSTEXPR_14 long double get_uint_max() { + static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8, + "Bytes must be a power of 2 below 8."); - IF_CONSTEXPR(sizeof(unsigned char) == Bytes) - { + IF_CONSTEXPR(sizeof(unsigned char) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned short) == Bytes) - { + IF_CONSTEXPR(sizeof(unsigned short) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned int) == Bytes) - { + IF_CONSTEXPR(sizeof(unsigned int) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) - { + IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) { return (long double)std::numeric_limits::max(); } - IF_CONSTEXPR(sizeof(unsigned long long int) == Bytes) - { + IF_CONSTEXPR(sizeof(unsigned long long int) == Bytes) { return (long double)std::numeric_limits::max(); } @@ -5312,17 +5246,17 @@ namespace csv * the exponential part of a number written (possibly) in scientific notation * parse the exponent */ - HEDLEY_PRIVATE CONSTEXPR_14 DataType - _process_potential_exponential(csv::string_view exponential_part, const long double& coeff, long double* const out) - { + HEDLEY_PRIVATE CONSTEXPR_14 + DataType _process_potential_exponential( + csv::string_view exponential_part, + const long double& coeff, + long double * const out) { long double exponent = 0; auto result = data_type(exponential_part, &exponent); // Exponents in scientific notation should not be decimal numbers - if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) - { - if (out) - *out = coeff * pow10(exponent); + if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) { + if (out) *out = coeff * pow10(exponent); return DataType::CSV_DOUBLE; } @@ -5332,8 +5266,8 @@ namespace csv /** Given the absolute value of an integer, determine what numeric type * it fits in */ - HEDLEY_PRIVATE HEDLEY_PURE CONSTEXPR_14 DataType _determine_integral_type(const long double& number) noexcept - { + HEDLEY_PRIVATE HEDLEY_PURE CONSTEXPR_14 + DataType _determine_integral_type(const long double& number) noexcept { // We can assume number is always non-negative assert(number >= 0); @@ -5361,41 +5295,40 @@ namespace csv * get stored */ CONSTEXPR_14 - DataType data_type(csv::string_view in, long double* const out) - { + DataType data_type(csv::string_view in, long double* const out) { // Empty string --> NULL if (in.size() == 0) return DataType::CSV_NULL; - bool ws_allowed = true, neg_allowed = true, dot_allowed = true, digit_allowed = true, has_digit = false, prob_float = false; + bool ws_allowed = true, + neg_allowed = true, + dot_allowed = true, + digit_allowed = true, + has_digit = false, + prob_float = false; unsigned places_after_decimal = 0; - long double integral_part = 0, decimal_part = 0; + long double integral_part = 0, + decimal_part = 0; - for (size_t i = 0, ilen = in.size(); i < ilen; i++) - { + for (size_t i = 0, ilen = in.size(); i < ilen; i++) { const char& current = in[i]; - switch (current) - { + switch (current) { case ' ': - if (!ws_allowed) - { - if (isdigit(in[i - 1])) - { + if (!ws_allowed) { + if (isdigit(in[i - 1])) { digit_allowed = false; ws_allowed = true; } - else - { + else { // Ex: '510 123 4567' return DataType::CSV_STRING; } } break; case '-': - if (!neg_allowed) - { + if (!neg_allowed) { // Ex: '510-123-4567' return DataType::CSV_STRING; } @@ -5403,8 +5336,7 @@ namespace csv neg_allowed = false; break; case '.': - if (!dot_allowed) - { + if (!dot_allowed) { return DataType::CSV_STRING; } @@ -5414,29 +5346,27 @@ namespace csv case 'e': case 'E': // Process scientific notation - if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) - { + if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) { size_t exponent_start_idx = i + 1; prob_float = true; // Strip out plus sign - if (in[i + 1] == '+') - { + if (in[i + 1] == '+') { exponent_start_idx++; } return _process_potential_exponential( in.substr(exponent_start_idx), neg_allowed ? integral_part + decimal_part : -(integral_part + decimal_part), - out); + out + ); } return DataType::CSV_STRING; break; default: short digit = static_cast(current - '0'); - if (digit >= 0 && digit <= 9) - { + if (digit >= 0 && digit <= 9) { // Process digit has_digit = true; @@ -5451,19 +5381,16 @@ namespace csv else integral_part = (integral_part * 10) + digit; } - else - { + else { return DataType::CSV_STRING; } } } // No non-numeric/non-whitespace characters found - if (has_digit) - { + if (has_digit) { long double number = integral_part + decimal_part; - if (out) - { + if (out) { *out = neg_allowed ? number : -number; } @@ -5473,28 +5400,25 @@ namespace csv // Just whitespace return DataType::CSV_NULL; } - } // namespace internals -} // namespace csv + } +} -namespace csv -{ - namespace internals - { +namespace csv { + namespace internals { class IBasicCSVParser; static const std::string ERROR_NAN = "Not a number."; static const std::string ERROR_OVERFLOW = "Overflow error."; - static const std::string ERROR_FLOAT_TO_INT = "Attempted to convert a floating point value to an integral type."; + static const std::string ERROR_FLOAT_TO_INT = + "Attempted to convert a floating point value to an integral type."; static const std::string ERROR_NEG_TO_UNSIGNED = "Negative numbers cannot be converted to unsigned types."; - + std::string json_escape_string(csv::string_view s) noexcept; /** A barebones class used for describing CSV fields */ - struct RawCSVField - { + struct RawCSVField { RawCSVField() = default; - RawCSVField(size_t _start, size_t _length, bool _double_quote = false) - { + RawCSVField(size_t _start, size_t _length, bool _double_quote = false) { start = _start; length = _length; has_double_quote = _double_quote; @@ -5504,7 +5428,7 @@ namespace csv size_t start; /** The length of the row, ignoring quote escape characters */ - size_t length; + size_t length; /** Whether or not the field contains an escaped quote */ bool has_double_quote; @@ -5521,13 +5445,11 @@ namespace csv * as long as the writing thread does not actively touch fields which are being * read. */ - class CSVFieldList - { + class CSVFieldList { public: /** Construct a CSVFieldList which allocates blocks of a certain size */ - CSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) - : _single_buffer_capacity(single_buffer_capacity) - { + CSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) : + _single_buffer_capacity(single_buffer_capacity) { this->allocate(); } @@ -5535,25 +5457,21 @@ namespace csv CSVFieldList(const CSVFieldList& other) = delete; // CSVFieldArrays may be moved - CSVFieldList(CSVFieldList&& other) - : _single_buffer_capacity(other._single_buffer_capacity) - { + CSVFieldList(CSVFieldList&& other) : + _single_buffer_capacity(other._single_buffer_capacity) { buffers = std::move(other.buffers); _current_buffer_size = other._current_buffer_size; _back = other._back; } - ~CSVFieldList() - { + ~CSVFieldList() { for (auto& buffer : buffers) delete[] buffer; } - template - void emplace_back(Args&&... args) - { - if (this->_current_buffer_size == this->_single_buffer_capacity) - { + template + void emplace_back(Args&&... args) { + if (this->_current_buffer_size == this->_single_buffer_capacity) { this->allocate(); } @@ -5561,8 +5479,7 @@ namespace csv _current_buffer_size++; } - size_t size() const noexcept - { + size_t size() const noexcept { return this->_current_buffer_size + ((this->buffers.size() - 1) * this->_single_buffer_capacity); } @@ -5583,9 +5500,9 @@ namespace csv void allocate(); }; + /** A class for storing raw CSV data and associated metadata */ - struct RawCSVData - { + struct RawCSVData { std::shared_ptr _data = nullptr; csv::string_view data = ""; @@ -5602,95 +5519,80 @@ namespace csv }; using RawCSVDataPtr = std::shared_ptr; - } // namespace internals + } /** - * @class CSVField - * @brief Data type representing individual CSV values. - * CSVFields can be obtained by using CSVRow::operator[] - */ - class CSVField - { + * @class CSVField + * @brief Data type representing individual CSV values. + * CSVFields can be obtained by using CSVRow::operator[] + */ + class CSVField { public: /** Constructs a CSVField from a string_view */ - constexpr explicit CSVField(csv::string_view _sv) noexcept - : sv(_sv){}; + constexpr explicit CSVField(csv::string_view _sv) noexcept : sv(_sv) { }; - operator std::string() const - { + operator std::string() const { return std::string(" ") + std::string(this->sv); } /** Returns the value casted to the requested type, performing type checking before. - * - * \par Valid options for T - * - std::string or csv::string_view - * - signed integral types (signed char, short, int, long int, long long int) - * - floating point types (float, double, long double) - * - unsigned integers are not supported at this time, but may be in a later release - * - * \par Invalid conversions - * - Converting non-numeric values to any numeric type - * - Converting floating point values to integers - * - Converting a large integer to a smaller type that will not hold it - * - * @note This method is capable of parsing scientific E-notation. - * See [this page](md_docs_source_scientific_notation.html) - * for more details. - * - * @throws std::runtime_error Thrown if an invalid conversion is performed. - * - * @warning Currently, conversions to floating point types are not - * checked for loss of precision - * - * @warning Any string_views returned are only guaranteed to be valid - * if the parent CSVRow is still alive. If you are concerned - * about object lifetimes, then grab a std::string or a - * numeric value. - * - */ - template - T get() - { - IF_CONSTEXPR(std::is_arithmetic::value) - { + * + * \par Valid options for T + * - std::string or csv::string_view + * - signed integral types (signed char, short, int, long int, long long int) + * - floating point types (float, double, long double) + * - unsigned integers are not supported at this time, but may be in a later release + * + * \par Invalid conversions + * - Converting non-numeric values to any numeric type + * - Converting floating point values to integers + * - Converting a large integer to a smaller type that will not hold it + * + * @note This method is capable of parsing scientific E-notation. + * See [this page](md_docs_source_scientific_notation.html) + * for more details. + * + * @throws std::runtime_error Thrown if an invalid conversion is performed. + * + * @warning Currently, conversions to floating point types are not + * checked for loss of precision + * + * @warning Any string_views returned are only guaranteed to be valid + * if the parent CSVRow is still alive. If you are concerned + * about object lifetimes, then grab a std::string or a + * numeric value. + * + */ + template T get() { + IF_CONSTEXPR(std::is_arithmetic::value) { // Note: this->type() also converts the CSV value to float - if (this->type() <= DataType::CSV_STRING) - { + if (this->type() <= DataType::CSV_STRING) { throw std::runtime_error(internals::ERROR_NAN); } } - IF_CONSTEXPR(std::is_integral::value) - { + IF_CONSTEXPR(std::is_integral::value) { // Note: this->is_float() also converts the CSV value to float - if (this->is_float()) - { + if (this->is_float()) { throw std::runtime_error(internals::ERROR_FLOAT_TO_INT); } - IF_CONSTEXPR(std::is_unsigned::value) - { - if (this->value < 0) - { + IF_CONSTEXPR(std::is_unsigned::value) { + if (this->value < 0) { throw std::runtime_error(internals::ERROR_NEG_TO_UNSIGNED); } } } // Allow fallthrough from previous if branch - IF_CONSTEXPR(!std::is_floating_point::value) - { - IF_CONSTEXPR(std::is_unsigned::value) - { + IF_CONSTEXPR(!std::is_floating_point::value) { + IF_CONSTEXPR(std::is_unsigned::value) { // Quick hack to perform correct unsigned integer boundary checks - if (this->value > internals::get_uint_max()) - { + if (this->value > internals::get_uint_max()) { throw std::runtime_error(internals::ERROR_OVERFLOW); } } - else if (internals::type_num() < this->_type) - { + else if (internals::type_num() < this->_type) { throw std::runtime_error(internals::ERROR_OVERFLOW); } } @@ -5717,12 +5619,11 @@ namespace csv template CONSTEXPR_14 bool operator==(T other) const noexcept { - static_assert(std::is_arithmetic::value, "T should be a numeric value."); + static_assert(std::is_arithmetic::value, + "T should be a numeric value."); - if (this->_type != DataType::UNKNOWN) - { - if (this->_type == DataType::CSV_STRING) - { + if (this->_type != DataType::UNKNOWN) { + if (this->_type == DataType::CSV_STRING) { return false; } @@ -5730,8 +5631,7 @@ namespace csv } long double out = 0; - if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) - { + if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) { return false; } @@ -5739,95 +5639,62 @@ namespace csv } /** Return a string view over the field's contents */ - CONSTEXPR csv::string_view get_sv() const noexcept - { - return this->sv; - } + CONSTEXPR csv::string_view get_sv() const noexcept { return this->sv; } /** Returns true if field is an empty string or string of whitespace characters */ - CONSTEXPR_14 bool is_null() noexcept - { - return type() == DataType::CSV_NULL; - } + CONSTEXPR_14 bool is_null() noexcept { return type() == DataType::CSV_NULL; } /** Returns true if field is a non-numeric, non-empty string */ - CONSTEXPR_14 bool is_str() noexcept - { - return type() == DataType::CSV_STRING; - } + CONSTEXPR_14 bool is_str() noexcept { return type() == DataType::CSV_STRING; } /** Returns true if field is an integer or float */ - CONSTEXPR_14 bool is_num() noexcept - { - return type() >= DataType::CSV_INT8; - } + CONSTEXPR_14 bool is_num() noexcept { return type() >= DataType::CSV_INT8; } /** Returns true if field is an integer */ - CONSTEXPR_14 bool is_int() noexcept - { + CONSTEXPR_14 bool is_int() noexcept { return (type() >= DataType::CSV_INT8) && (type() <= DataType::CSV_INT64); } /** Returns true if field is a floating point value */ - CONSTEXPR_14 bool is_float() noexcept - { - return type() == DataType::CSV_DOUBLE; - }; + CONSTEXPR_14 bool is_float() noexcept { return type() == DataType::CSV_DOUBLE; }; /** Return the type of the underlying CSV data */ - CONSTEXPR_14 DataType type() noexcept - { + CONSTEXPR_14 DataType type() noexcept { this->get_value(); return _type; } private: - long double value = 0; /**< Cached numeric value */ + long double value = 0; /**< Cached numeric value */ csv::string_view sv = ""; /**< A pointer to this field's text */ DataType _type = DataType::UNKNOWN; /**< Cached data type value */ - CONSTEXPR_14 void get_value() noexcept - { + CONSTEXPR_14 void get_value() noexcept { /* Check to see if value has been cached previously, if not * evaluate it */ - if ((int)_type < 0) - { + if ((int)_type < 0) { this->_type = internals::data_type(this->sv, &this->value); } } }; /** Data structure for representing CSV rows */ - class CSVRow - { + class CSVRow { public: friend internals::IBasicCSVParser; CSVRow() = default; - + /** Construct a CSVRow from a RawCSVDataPtr */ - CSVRow(internals::RawCSVDataPtr _data) - : data(_data) - { - } + CSVRow(internals::RawCSVDataPtr _data) : data(_data) {} CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds) - : data(_data) - , data_start(_data_start) - , fields_start(_field_bounds) - { - } + : data(_data), data_start(_data_start), fields_start(_field_bounds) {} /** Indicates whether row is empty or not */ - CONSTEXPR bool empty() const noexcept - { - return this->size() == 0; - } + CONSTEXPR bool empty() const noexcept { return this->size() == 0; } /** Return the number of fields in this row */ - CONSTEXPR size_t size() const noexcept - { - return row_length; - } + CONSTEXPR size_t size() const noexcept { return row_length; } /** @name Value Retrieval */ ///@{ @@ -5837,8 +5704,7 @@ namespace csv std::string to_json_array(const std::vector& subset = {}) const; /** Retrieve this row's associated column names */ - std::vector get_col_names() const - { + std::vector get_col_names() const { return this->data->col_names->get_col_names(); } @@ -5852,8 +5718,7 @@ namespace csv /** A random access iterator over the contents of a CSV row. * Each iterator points to a CSVField. */ - class iterator - { + class iterator { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVField; @@ -5864,10 +5729,10 @@ namespace csv #ifdef _MSC_BUILD using pointer = std::shared_ptr; #else - using pointer = CSVField*; + using pointer = CSVField * ; #endif - using reference = CSVField&; + using reference = CSVField & ; using iterator_category = std::random_access_iterator_tag; #endif iterator(const CSVRow*, int i); @@ -5883,24 +5748,20 @@ namespace csv iterator operator-(difference_type n) const; /** Two iterators are equal if they point to the same field */ - CONSTEXPR bool operator==(const iterator& other) const noexcept - { + CONSTEXPR bool operator==(const iterator& other) const noexcept { return this->i == other.i; }; - CONSTEXPR bool operator!=(const iterator& other) const noexcept - { - return !operator==(other); - } + CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } #ifndef NDEBUG friend CSVRow; #endif private: - const CSVRow* daddy = nullptr; // Pointer to parent + const CSVRow * daddy = nullptr; // Pointer to parent std::shared_ptr field = nullptr; // Current field pointed at - int i = 0; // Index of current field + int i = 0; // Index of current field }; /** A reverse iterator over the contents of a CSVRow. */ @@ -5909,7 +5770,7 @@ namespace csv /** @name Iterators * @brief Each iterator points to a CSVField object. */ - ///@{ + ///@{ iterator begin() const; iterator end() const noexcept; reverse_iterator rbegin() const noexcept; @@ -5937,8 +5798,7 @@ namespace csv #endif /** Retrieve this field's original string */ template<> - inline std::string CSVField::get() - { + inline std::string CSVField::get() { return std::string(this->sv); } @@ -5948,15 +5808,13 @@ namespace csv * CSVRow is still alive. */ template<> - CONSTEXPR_14 csv::string_view CSVField::get() - { + CONSTEXPR_14 csv::string_view CSVField::get() { return this->sv; } /** Retrieve this field's value as a long double */ template<> - CONSTEXPR_14 long double CSVField::get() - { + CONSTEXPR_14 long double CSVField::get() { if (!is_num()) throw std::runtime_error(internals::ERROR_NAN); @@ -5968,7 +5826,7 @@ namespace csv /** Compares the contents of this field to a string */ template<> - CONSTEXPR bool CSVField::operator==(const char* other) const noexcept + CONSTEXPR bool CSVField::operator==(const char * other) const noexcept { return this->sv == other; } @@ -5979,27 +5837,23 @@ namespace csv { return this->sv == other; } -} // namespace csv +} -inline std::ostream& operator<<(std::ostream& os, csv::CSVField const& value) -{ +inline std::ostream& operator << (std::ostream& os, csv::CSVField const& value) { os << std::string(value); return os; } -namespace csv -{ - namespace internals - { + +namespace csv { + namespace internals { /** Create a vector v where each index i corresponds to the * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ - HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) - { + HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) { std::array ret = {}; - for (int i = -128; i < 128; i++) - { + for (int i = -128; i < 128; i++) { const int arr_idx = i + 128; char ch = char(i); @@ -6018,8 +5872,7 @@ namespace csv * ASCII number for a character and, v[i + 128] labels it according to * the CSVReader::ParseFlags enum */ - HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) - { + HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) { std::array ret = make_parse_flags(delimiter); ret[(size_t)quote_char + 128] = ParseFlags::QUOTE; return ret; @@ -6029,19 +5882,15 @@ namespace csv * ASCII number for a character c and, v[i + 128] is true if * c is a whitespace character */ - HEDLEY_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) - { + HEDLEY_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) { std::array ret = {}; - for (int i = -128; i < 128; i++) - { + for (int i = -128; i < 128; i++) { const int arr_idx = i + 128; char ch = char(i); ret[arr_idx] = false; - for (size_t j = 0; j < n_chars; j++) - { - if (ws_chars[j] == ch) - { + for (size_t j = 0; j < n_chars; j++) { + if (ws_chars[j] == ch) { ret[arr_idx] = true; } } @@ -6050,8 +5899,7 @@ namespace csv return ret; } - inline WhitespaceMap make_ws_flags(const std::vector& flags) - { + inline WhitespaceMap make_ws_flags(const std::vector& flags) { return make_ws_flags(flags.data(), flags.size()); } @@ -6067,112 +5915,81 @@ namespace csv * to become populated */ template - class ThreadSafeDeque - { + class ThreadSafeDeque { public: - ThreadSafeDeque(size_t notify_size = 100) - : _notify_size(notify_size){}; - ThreadSafeDeque(const ThreadSafeDeque& other) - { + ThreadSafeDeque(size_t notify_size = 100) : _notify_size(notify_size) {}; + ThreadSafeDeque(const ThreadSafeDeque& other) { this->data = other.data; this->_notify_size = other._notify_size; } - ThreadSafeDeque(const std::deque& source) - : ThreadSafeDeque() - { + ThreadSafeDeque(const std::deque& source) : ThreadSafeDeque() { this->data = source; } - void clear() noexcept - { - this->data.clear(); - } + void clear() noexcept { this->data.clear(); } - bool empty() const noexcept - { + bool empty() const noexcept { return this->data.empty(); } - T& front() noexcept - { + T& front() noexcept { return this->data.front(); } - T& operator[](size_t n) - { + T& operator[](size_t n) { return this->data[n]; } - void push_back(T&& item) - { + void push_back(T&& item) { std::lock_guard lock{ this->_lock }; this->data.push_back(std::move(item)); - if (this->size() >= _notify_size) - { + if (this->size() >= _notify_size) { this->_cond.notify_all(); } } - T pop_front() noexcept - { + T pop_front() noexcept { std::lock_guard lock{ this->_lock }; T item = std::move(data.front()); data.pop_front(); return item; } - size_t size() const noexcept - { - return this->data.size(); - } + size_t size() const noexcept { return this->data.size(); } /** Returns true if a thread is actively pushing items to this deque */ - constexpr bool is_waitable() const noexcept - { - return this->_is_waitable; - } + constexpr bool is_waitable() const noexcept { return this->_is_waitable; } /** Wait for an item to become available */ - void wait() - { - if (!is_waitable()) - { + void wait() { + if (!is_waitable()) { return; } std::unique_lock lock{ this->_lock }; - this->_cond.wait( - lock, - [this] - { - return this->size() >= _notify_size || !this->is_waitable(); - }); + this->_cond.wait(lock, [this] { return this->size() >= _notify_size || !this->is_waitable(); }); lock.unlock(); } - typename std::deque::iterator begin() noexcept - { + typename std::deque::iterator begin() noexcept { return this->data.begin(); } - typename std::deque::iterator end() noexcept - { + typename std::deque::iterator end() noexcept { return this->data.end(); } /** Tell listeners that this deque is actively being pushed to */ - void notify_all() - { + void notify_all() { std::unique_lock lock{ this->_lock }; this->_is_waitable = true; this->_cond.notify_all(); } /** Tell all listeners to stop */ - void kill_all() - { + void kill_all() { std::unique_lock lock{ this->_lock }; this->_is_waitable = false; this->_cond.notify_all(); @@ -6187,37 +6004,29 @@ namespace csv }; constexpr const int UNINITIALIZED_FIELD = -1; - } // namespace internals + } /** Standard type for storing collection of rows */ using RowCollection = internals::ThreadSafeDeque; - namespace internals - { + namespace internals { /** Abstract base class which provides CSV parsing logic. * * Concrete implementations may customize this logic across * different input sources, such as memory mapped files, stringstreams, * etc... */ - class IBasicCSVParser - { + class IBasicCSVParser { public: IBasicCSVParser() = default; IBasicCSVParser(const CSVFormat&, const ColNamesPtr&); - IBasicCSVParser(const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags) - : _parse_flags(parse_flags) - , _ws_flags(ws_flags){}; + IBasicCSVParser(const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags + ) : _parse_flags(parse_flags), _ws_flags(ws_flags) {}; - virtual ~IBasicCSVParser() - { - } + virtual ~IBasicCSVParser() {} /** Whether or not we have reached the end of source */ - bool eof() - { - return this->_eof; - } + bool eof() { return this->_eof; } /** Parse the next block of data */ virtual void next(size_t bytes) = 0; @@ -6225,26 +6034,18 @@ namespace csv /** Indicate the last block of data has been parsed */ void end_feed(); - CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept - { + CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept { return _parse_flags.data()[ch + 128]; } - CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept - { + CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept { return quote_escape_flag(parse_flag(ch), this->quote_escape); } /** Whether or not this CSV has a UTF-8 byte order mark */ - CONSTEXPR bool utf8_bom() const - { - return this->_utf8_bom; - } + CONSTEXPR bool utf8_bom() const { return this->_utf8_bom; } - void set_output(RowCollection& rows) - { - this->_records = &rows; - } + void set_output(RowCollection& rows) { this->_records = &rows; } protected: /** @name Current Parser State */ @@ -6269,10 +6070,7 @@ namespace csv ///@} /** Whether or not source needs to be read in chunks */ - CONSTEXPR bool no_chunk() const - { - return this->source_size < ITERATION_CHUNK_SIZE; - } + CONSTEXPR bool no_chunk() const { return this->source_size < ITERATION_CHUNK_SIZE; } /** Parse the current chunk of data * * @@ -6282,7 +6080,6 @@ namespace csv /** Create a new RawCSVDataPtr for a new chunk of data */ void reset_data_ptr(); - private: /** An array where the (i + 128)th slot determines whether ASCII character i should * be trimmed @@ -6301,13 +6098,11 @@ namespace csv /** Where complete rows should be pushed to */ RowCollection* _records = nullptr; - CONSTEXPR_17 bool ws_flag(const char ch) const noexcept - { + CONSTEXPR_17 bool ws_flag(const char ch) const noexcept { return _ws_flags.data()[ch + 128]; } - size_t& current_row_start() - { + size_t& current_row_start() { return this->current_row.data_start; } @@ -6327,33 +6122,32 @@ namespace csv * or an `std::ifstream` */ template - class StreamParser : public IBasicCSVParser - { + class StreamParser: public IBasicCSVParser { using RowCollection = ThreadSafeDeque; public: - StreamParser(TStream& source, const CSVFormat& format, const ColNamesPtr& col_names = nullptr) - : IBasicCSVParser(format, col_names) - , _source(std::move(source)){}; + StreamParser(TStream& source, + const CSVFormat& format, + const ColNamesPtr& col_names = nullptr + ) : IBasicCSVParser(format, col_names), _source(std::move(source)) {}; - StreamParser(TStream& source, internals::ParseFlagMap parse_flags, internals::WhitespaceMap ws_flags) - : IBasicCSVParser(parse_flags, ws_flags) - , _source(std::move(source)){}; + StreamParser( + TStream& source, + internals::ParseFlagMap parse_flags, + internals::WhitespaceMap ws_flags) : + IBasicCSVParser(parse_flags, ws_flags), + _source(std::move(source)) + {}; - ~StreamParser() - { - } + ~StreamParser() {} - void next(size_t bytes = ITERATION_CHUNK_SIZE) override - { - if (this->eof()) - return; + void next(size_t bytes = ITERATION_CHUNK_SIZE) override { + if (this->eof()) return; this->reset_data_ptr(); this->data_ptr->_data = std::make_shared(); - if (source_size == 0) - { + if (source_size == 0) { const auto start = _source.tellg(); _source.seekg(0, std::ios::end); const auto end = _source.tellg(); @@ -6377,13 +6171,11 @@ namespace csv this->current_row = CSVRow(this->data_ptr); size_t remainder = this->parse(); - if (stream_pos == source_size || no_chunk()) - { + if (stream_pos == source_size || no_chunk()) { this->_eof = true; this->end_feed(); } - else - { + else { this->stream_pos -= (length - remainder); } } @@ -6402,19 +6194,17 @@ namespace csv * re-align each memory map to the beginning of a CSV row. * */ - class MmapParser : public IBasicCSVParser - { + class MmapParser : public IBasicCSVParser { public: - MmapParser(csv::string_view filename, const CSVFormat& format, const ColNamesPtr& col_names = nullptr) - : IBasicCSVParser(format, col_names) - { + MmapParser(csv::string_view filename, + const CSVFormat& format, + const ColNamesPtr& col_names = nullptr + ) : IBasicCSVParser(format, col_names) { this->_filename = filename.data(); this->source_size = get_file_size(filename); }; - ~MmapParser() - { - } + ~MmapParser() {} void next(size_t bytes) override; @@ -6422,21 +6212,19 @@ namespace csv std::string _filename; size_t mmap_pos = 0; }; - } // namespace internals -} // namespace csv + } +} + /** The all encompassing namespace */ -namespace csv -{ +namespace csv { /** Stuff that is generally not of interest to end-users */ - namespace internals - { + namespace internals { std::string format_row(const std::vector& row, csv::string_view delim = ", "); - std::vector _get_col_names(csv::string_view head, const CSVFormat format = CSVFormat::guess_csv()); + std::vector _get_col_names( csv::string_view head, const CSVFormat format = CSVFormat::guess_csv()); - struct GuessScore - { + struct GuessScore { double score; size_t header; }; @@ -6444,12 +6232,15 @@ namespace csv CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format); CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); - } // namespace internals + } - std::vector get_col_names(csv::string_view filename, const CSVFormat format = CSVFormat::guess_csv()); + std::vector get_col_names( + csv::string_view filename, + const CSVFormat format = CSVFormat::guess_csv()); /** Guess the delimiter used by a delimiter-separated values file */ - CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); + CSVGuessResult guess_format(csv::string_view filename, + const std::vector& delims = { ',', '|', '\t', ';', '^', '~' }); /** @class CSVReader * @brief Main class for parsing CSVs from files and in-memory sources @@ -6458,8 +6249,7 @@ namespace csv * - By default, rows that are too short or too long are dropped * - Custom behavior can be defined by overriding bad_row_handler in a subclass */ - class CSVReader - { + class CSVReader { public: /** * An input iterator capable of handling large files. @@ -6471,61 +6261,48 @@ namespace csv * @par Using with `` library * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 2 */ - class iterator - { + class iterator { public: -#ifndef DOXYGEN_SHOULD_SKIP_THIS + #ifndef DOXYGEN_SHOULD_SKIP_THIS using value_type = CSVRow; using difference_type = std::ptrdiff_t; - using pointer = CSVRow*; - using reference = CSVRow&; + using pointer = CSVRow * ; + using reference = CSVRow & ; using iterator_category = std::input_iterator_tag; -#endif + #endif iterator() = default; - iterator(CSVReader* reader) - : daddy(reader){}; + iterator(CSVReader* reader) : daddy(reader) {}; iterator(CSVReader*, CSVRow&&); /** Access the CSVRow held by the iterator */ - CONSTEXPR_14 reference operator*() - { - return this->row; - } + CONSTEXPR_14 reference operator*() { return this->row; } /** Return a pointer to the CSVRow the iterator has stopped at */ - CONSTEXPR_14 pointer operator->() - { - return &(this->row); - } + CONSTEXPR_14 pointer operator->() { return &(this->row); } - iterator& operator++(); /**< Pre-increment iterator */ + iterator& operator++(); /**< Pre-increment iterator */ iterator operator++(int); /**< Post-increment ierator */ iterator& operator--(); /** Returns true if iterators were constructed from the same CSVReader * and point to the same row */ - CONSTEXPR bool operator==(const iterator& other) const noexcept - { + CONSTEXPR bool operator==(const iterator& other) const noexcept { return (this->daddy == other.daddy) && (this->i == other.i); } - CONSTEXPR bool operator!=(const iterator& other) const noexcept - { - return !operator==(other); - } - + CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); } private: - CSVReader* daddy = nullptr; // Pointer to parent - CSVRow row; // Current row - size_t i = 0; // Index of current row + CSVReader * daddy = nullptr; // Pointer to parent + CSVRow row; // Current row + size_t i = 0; // Index of current row }; /** @name Constructors * Constructors for iterating over large files and parsing in-memory sources. */ - ///@{ + ///@{ CSVReader(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); /** Allows parsing stream sources such as `std::stringstream` or `std::ifstream` @@ -6534,43 +6311,38 @@ namespace csv * @note Currently this constructor requires special CSV dialects to be manually * specified. */ - template::value, int> = 0> - CSVReader(TStream& source, CSVFormat format = CSVFormat()) - : _format(format) - { + template::value, int> = 0> + CSVReader(TStream& source, CSVFormat format = CSVFormat()) : _format(format) { using Parser = internals::StreamParser; if (!format.col_names.empty()) this->set_col_names(format.col_names); - this->parser = std::unique_ptr(new Parser(source, format, col_names)); // For C++11 + this->parser = std::unique_ptr( + new Parser(source, format, col_names)); // For C++11 this->initial_read(); } ///@} CSVReader(const CSVReader&) = delete; // No copy constructor - CSVReader(CSVReader&&) = default; // Move constructor + CSVReader(CSVReader&&) = default; // Move constructor CSVReader& operator=(const CSVReader&) = delete; // No copy assignment CSVReader& operator=(CSVReader&& other) = default; - ~CSVReader() - { - if (this->read_csv_worker.joinable()) - { + ~CSVReader() { + if (this->read_csv_worker.joinable()) { this->read_csv_worker.join(); } } /** @name Retrieving CSV Rows */ ///@{ - bool read_row(CSVRow& row); + bool read_row(CSVRow &row); iterator begin(); HEDLEY_CONST iterator end() const noexcept; /** Returns true if we have reached end of file */ - bool eof() const noexcept - { - return this->parser->eof(); - }; + bool eof() const noexcept { return this->parser->eof(); }; ///@} /** @name CSV Metadata */ @@ -6588,22 +6360,13 @@ namespace csv * @note Gives an accurate answer regardless of when it is called. * */ - CONSTEXPR bool empty() const noexcept - { - return this->n_rows() == 0; - } + CONSTEXPR bool empty() const noexcept { return this->n_rows() == 0; } /** Retrieves the number of rows that have been read so far */ - CONSTEXPR size_t n_rows() const noexcept - { - return this->_n_rows; - } + CONSTEXPR size_t n_rows() const noexcept { return this->_n_rows; } /** Whether or not CSV was prefixed with a UTF-8 bom */ - bool utf8_bom() const noexcept - { - return this->parser->utf8_bom(); - } + bool utf8_bom() const noexcept { return this->parser->utf8_bom(); } ///@} protected: @@ -6631,9 +6394,9 @@ namespace csv std::unique_ptr parser = nullptr; /** Queue of parsed CSV rows */ - std::unique_ptr records{ new RowCollection(100) }; + std::unique_ptr records{new RowCollection(100)}; - size_t n_cols = 0; /**< The number of columns in this CSV */ + size_t n_cols = 0; /**< The number of columns in this CSV */ size_t _n_rows = 0; /**< How many rows (minus header) have been read so far */ /** @name Multi-Threaded File Reading Functions */ @@ -6653,34 +6416,31 @@ namespace csv ///@} /** Read initial chunk to get metadata */ - void initial_read() - { + void initial_read() { this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); this->read_csv_worker.join(); } void trim_header(); }; -} // namespace csv +} /** @file * Calculates statistics from CSV files */ -#include #include +#include #include -namespace csv -{ +namespace csv { /** Class for calculating statistics from CSV files and in-memory sources * * **Example** * \include programs/csv_stats.cpp * */ - class CSVStat - { + class CSVStat { public: using FreqCount = std::unordered_map; using TypeCount = std::unordered_map; @@ -6692,14 +6452,12 @@ namespace csv std::vector get_counts() const; std::vector get_dtypes() const; - std::vector get_col_names() const - { + std::vector get_col_names() const { return this->reader.get_col_names(); } CSVStat(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv()); CSVStat(std::stringstream& source, CSVFormat format = CSVFormat()); - private: // An array of rolling averages // Each index corresponds to the rolling mean for the column at said index @@ -6724,30 +6482,28 @@ namespace csv CSVReader reader; std::deque records = {}; }; -} // namespace csv +} #include #include #include -namespace csv -{ +namespace csv { /** Returned by get_file_info() */ - struct CSVFileInfo - { - std::string filename; /**< Filename */ + struct CSVFileInfo { + std::string filename; /**< Filename */ std::vector col_names; /**< CSV column names */ - char delim; /**< Delimiting character */ - size_t n_rows; /**< Number of rows in a file */ - size_t n_cols; /**< Number of columns in a CSV */ + char delim; /**< Delimiting character */ + size_t n_rows; /**< Number of rows in a file */ + size_t n_cols; /**< Number of columns in a CSV */ }; /** @name Shorthand Parsing Functions * @brief Convienience functions for parsing small strings */ - ///@{ - CSVReader operator""_csv(const char*, size_t); - CSVReader operator""_csv_no_header(const char*, size_t); + ///@{ + CSVReader operator ""_csv(const char*, size_t); + CSVReader operator ""_csv_no_header(const char*, size_t); CSVReader parse(csv::string_view in, CSVFormat format = CSVFormat()); CSVReader parse_no_header(csv::string_view in); ///@} @@ -6756,12 +6512,13 @@ namespace csv ///@{ std::unordered_map csv_data_types(const std::string&); CSVFileInfo get_file_info(const std::string& filename); - int get_col_pos(csv::string_view filename, csv::string_view col_name, const CSVFormat& format = CSVFormat::guess_csv()); + int get_col_pos(csv::string_view filename, csv::string_view col_name, + const CSVFormat& format = CSVFormat::guess_csv()); ///@} -} // namespace csv +} /** @file - * A standalone header file for writing delimiter-separated files - */ + * A standalone header file for writing delimiter-separated files + */ #include #include @@ -6770,23 +6527,20 @@ namespace csv #include #include -namespace csv -{ - namespace internals - { + +namespace csv { + namespace internals { static int DECIMAL_PLACES = 5; /** to_string() for unsigned integers */ - template::value, int> = 0> - inline std::string to_string(T value) - { + template::value, int> = 0> + inline std::string to_string(T value) { std::string digits_reverse = ""; - if (value == 0) - return "0"; + if (value == 0) return "0"; - while (value > 0) - { + while (value > 0) { digits_reverse += (char)('0' + (value % 10)); value /= 10; } @@ -6795,9 +6549,11 @@ namespace csv } /** to_string() for signed integers */ - template::value && std::is_signed::value, int> = 0> - inline std::string to_string(T value) - { + template< + typename T, + csv::enable_if_t::value && std::is_signed::value, int> = 0 + > + inline std::string to_string(T value) { if (value >= 0) return to_string((size_t)value); @@ -6805,69 +6561,64 @@ namespace csv } /** to_string() for floating point numbers */ - template::value, int> = 0> - inline std::string to_string(T value) - { - std::string result; + template< + typename T, + csv::enable_if_t::value, int> = 0 + > + inline std::string to_string(T value) { + std::string result; - T integral_part; - T fractional_part = std::abs(std::modf(value, &integral_part)); - integral_part = std::abs(integral_part); + T integral_part; + T fractional_part = std::abs(std::modf(value, &integral_part)); + integral_part = std::abs(integral_part); - // Integral part - if (value < 0) - result = "-"; + // Integral part + if (value < 0) result = "-"; - if (integral_part == 0) - { - result = "0"; - } - else - { - for (int n_digits = (int)(std::log(integral_part) / std::log(10)); n_digits + 1 > 0; n_digits--) - { - int digit = (int)(std::fmod(integral_part, pow10(n_digits + 1)) / pow10(n_digits)); - result += (char)('0' + digit); + if (integral_part == 0) { + result = "0"; + } + else { + for (int n_digits = (int)(std::log(integral_part) / std::log(10)); + n_digits + 1 > 0; n_digits --) { + int digit = (int)(std::fmod(integral_part, pow10(n_digits + 1)) / pow10(n_digits)); + result += (char)('0' + digit); + } } - } - // Decimal part - result += "."; + // Decimal part + result += "."; - if (fractional_part > 0) - { - fractional_part *= (T)(pow10(DECIMAL_PLACES)); - for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) - { - int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1)); - result += (char)('0' + digit); + if (fractional_part > 0) { + fractional_part *= (T)(pow10(DECIMAL_PLACES)); + for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) { + int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1)); + result += (char)('0' + digit); + } + } + else { + result += "0"; } - } - else - { - result += "0"; - } - return result; + return result; } - } // namespace internals + } /** Sets how many places after the decimal will be written for floating point numbers * * @param precision Number of decimal places */ - inline static void set_decimal_places(int precision) - { + inline static void set_decimal_places(int precision) { internals::DECIMAL_PLACES = precision; } /** @name CSV Writing */ ///@{ - /** + /** * Class for writing delimiter separated values files * * To write formatted strings, one should - * -# Initialize a DelimWriter with respect to some output stream + * -# Initialize a DelimWriter with respect to some output stream * -# Call write_row() on std::vectors of unformatted text * * @tparam OutputStream The output stream, e.g. `std::ofstream`, `std::stringstream` @@ -6889,31 +6640,27 @@ namespace csv * @snippet test_write_csv.cpp CSV Writer Tuple Example */ template - class DelimWriter - { + class DelimWriter { public: /** Construct a DelimWriter over the specified output stream * * @param _out Stream to write to * @param _quote_minimal Limit field quoting to only when necessary - */ + */ DelimWriter(OutputStream& _out, bool _quote_minimal = true) - : out(_out) - , quote_minimal(_quote_minimal){}; + : out(_out), quote_minimal(_quote_minimal) {}; /** Construct a DelimWriter over the file * * @param[out] filename File to write to */ - DelimWriter(const std::string& filename) - : DelimWriter(std::ifstream(filename)){}; + DelimWriter(const std::string& filename) : DelimWriter(std::ifstream(filename)) {}; /** Destructor will flush remaining data * */ - ~DelimWriter() - { + ~DelimWriter() { out.flush(); } @@ -6926,13 +6673,10 @@ namespace csv * @return The current DelimWriter instance (allowing for operator chaining) */ template - DelimWriter& operator<<(const std::array& record) - { - for (size_t i = 0; i < Size; i++) - { + DelimWriter& operator<<(const std::array& record) { + for (size_t i = 0; i < Size; i++) { out << csv_escape(record[i]); - if (i + 1 != Size) - out << Delim; + if (i + 1 != Size) out << Delim; } end_out(); @@ -6941,34 +6685,28 @@ namespace csv /** @copydoc operator<< */ template - DelimWriter& operator<<(const std::tuple& record) - { + DelimWriter& operator<<(const std::tuple& record) { this->write_tuple<0, T...>(record); return *this; } /** * @tparam T A container such as std::vector, std::deque, or std::list - * + * * @copydoc operator<< */ template< - typename T, - typename Alloc, - template - class Container, + typename T, typename Alloc, template class Container, // Avoid conflicting with tuples with two elements - csv::enable_if_t::value, int> = 0> - DelimWriter& operator<<(const Container& record) - { + csv::enable_if_t::value, int> = 0 + > + DelimWriter& operator<<(const Container& record) { const size_t ilen = record.size(); size_t i = 0; - for (const auto& field : record) - { + for (const auto& field : record) { out << csv_escape(field); - if (i + 1 != ilen) - out << Delim; + if (i + 1 != ilen) out << Delim; i++; } @@ -6979,35 +6717,38 @@ namespace csv /** Flushes the written data * */ - void flush() - { + void flush() { out.flush(); } private: template< typename T, - csv::enable_if_t::value && !std::is_convertible::value, int> = 0> - std::string csv_escape(T in) - { + csv::enable_if_t< + !std::is_convertible::value + && !std::is_convertible::value + , int> = 0 + > + std::string csv_escape(T in) { return internals::to_string(in); } template< typename T, - csv::enable_if_t::value || std::is_convertible::value, int> = 0> - std::string csv_escape(T in) - { - IF_CONSTEXPR(std::is_convertible::value) - { + csv::enable_if_t< + std::is_convertible::value + || std::is_convertible::value + , int> = 0 + > + std::string csv_escape(T in) { + IF_CONSTEXPR(std::is_convertible::value) { return _csv_escape(in); } - + return _csv_escape(std::string(in)); } - std::string _csv_escape(csv::string_view in) - { + std::string _csv_escape(csv::string_view in) { /** Format a string to be RFC 4180-compliant * @param[in] in String to be CSV-formatted * @param[out] quote_minimal Only quote fields if necessary. @@ -7017,21 +6758,16 @@ namespace csv // Do we need a quote escape bool quote_escape = false; - for (auto ch : in) - { - if (ch == Quote || ch == Delim || ch == '\r' || ch == '\n') - { + for (auto ch : in) { + if (ch == Quote || ch == Delim || ch == '\r' || ch == '\n') { quote_escape = true; break; } } - if (!quote_escape) - { - if (quote_minimal) - return std::string(in); - else - { + if (!quote_escape) { + if (quote_minimal) return std::string(in); + else { std::string ret(1, Quote); ret += in.data(); ret += Quote; @@ -7041,12 +6777,9 @@ namespace csv // Start initial quote escape sequence std::string ret(1, Quote); - for (auto ch : in) - { - if (ch == Quote) - ret += std::string(2, Quote); - else - ret += ch; + for (auto ch: in) { + if (ch == Quote) ret += std::string(2, Quote); + else ret += ch; } // Finish off quote escape @@ -7056,31 +6789,28 @@ namespace csv /** Recurisve template for writing std::tuples */ template - typename std::enable_if < Index::type write_tuple(const std::tuple& record) - { + typename std::enable_if::type write_tuple(const std::tuple& record) { out << csv_escape(std::get(record)); - IF_CONSTEXPR(Index + 1 < sizeof...(T)) out << Delim; + IF_CONSTEXPR (Index + 1 < sizeof...(T)) out << Delim; this->write_tuple(record); } /** Base case for writing std::tuples */ template - typename std::enable_if::type write_tuple(const std::tuple& record) - { + typename std::enable_if::type write_tuple(const std::tuple& record) { (void)record; end_out(); } /** Ends a line in 'out' and flushes, if Flush is true.*/ - void end_out() - { + void end_out() { out << '\n'; IF_CONSTEXPR(Flush) out.flush(); } - OutputStream& out; + OutputStream & out; bool quote_minimal; }; @@ -7095,7 +6825,7 @@ namespace csv using CSVWriter = DelimWriter; /** Class for writing tab-separated values files - * + * * @sa csv::DelimWriter::write_row() * @sa csv::DelimWriter::operator<<() * @@ -7107,40 +6837,34 @@ namespace csv /** Return a csv::CSVWriter over the output stream */ template - inline CSVWriter make_csv_writer(OutputStream& out, bool quote_minimal = true) - { + inline CSVWriter make_csv_writer(OutputStream& out, bool quote_minimal=true) { return CSVWriter(out, quote_minimal); } /** Return a buffered csv::CSVWriter over the output stream (does not auto flush) */ template - inline CSVWriter make_csv_writer_buffered(OutputStream& out, bool quote_minimal = true) - { + inline CSVWriter make_csv_writer_buffered(OutputStream& out, bool quote_minimal=true) { return CSVWriter(out, quote_minimal); } /** Return a csv::TSVWriter over the output stream */ template - inline TSVWriter make_tsv_writer(OutputStream& out, bool quote_minimal = true) - { + inline TSVWriter make_tsv_writer(OutputStream& out, bool quote_minimal=true) { return TSVWriter(out, quote_minimal); } /** Return a buffered csv::TSVWriter over the output stream (does not auto flush) */ template - inline TSVWriter make_tsv_writer_buffered(OutputStream& out, bool quote_minimal = true) - { + inline TSVWriter make_tsv_writer_buffered(OutputStream& out, bool quote_minimal=true) { return TSVWriter(out, quote_minimal); } ///@} -} // namespace csv +} -namespace csv -{ - namespace internals - { - CSV_INLINE size_t get_file_size(csv::string_view filename) - { + +namespace csv { + namespace internals { + CSV_INLINE size_t get_file_size(csv::string_view filename) { std::ifstream infile(std::string(filename), std::ios::binary); const auto start = infile.tellg(); infile.seekg(0, std::ios::end); @@ -7149,21 +6873,18 @@ namespace csv return end - start; } - CSV_INLINE std::string get_csv_head(csv::string_view filename) - { + CSV_INLINE std::string get_csv_head(csv::string_view filename) { return get_csv_head(filename, get_file_size(filename)); } - CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) - { + CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) { const size_t bytes = 500000; std::error_code error; size_t length = std::min((size_t)file_size, bytes); auto mmap = mio::make_mmap_source(std::string(filename), 0, length, error); - if (error) - { + if (error) { throw std::runtime_error("Cannot open file " + std::string(filename)); } @@ -7173,31 +6894,32 @@ namespace csv #ifdef _MSC_VER #pragma region IBasicCVParser #endif - CSV_INLINE IBasicCSVParser::IBasicCSVParser(const CSVFormat& format, const ColNamesPtr& col_names) - : _col_names(col_names) - { - if (format.no_quote) - { + CSV_INLINE IBasicCSVParser::IBasicCSVParser( + const CSVFormat& format, + const ColNamesPtr& col_names + ) : _col_names(col_names) { + if (format.no_quote) { _parse_flags = internals::make_parse_flags(format.get_delim()); } - else - { + else { _parse_flags = internals::make_parse_flags(format.get_delim(), format.quote_char); } - _ws_flags = internals::make_ws_flags(format.trim_chars.data(), format.trim_chars.size()); + _ws_flags = internals::make_ws_flags( + format.trim_chars.data(), format.trim_chars.size() + ); } - CSV_INLINE void IBasicCSVParser::end_feed() - { + CSV_INLINE void IBasicCSVParser::end_feed() { using internals::ParseFlags; - bool empty_last_field = this->data_ptr && this->data_ptr->_data && !this->data_ptr->data.empty() && - parse_flag(this->data_ptr->data.back()) == ParseFlags::DELIMITER; + bool empty_last_field = this->data_ptr + && this->data_ptr->_data + && !this->data_ptr->data.empty() + && parse_flag(this->data_ptr->data.back()) == ParseFlags::DELIMITER; // Push field - if (this->field_length > 0 || empty_last_field) - { + if (this->field_length > 0 || empty_last_field) { this->push_field(); } @@ -7206,8 +6928,7 @@ namespace csv this->push_row(); } - CSV_INLINE void IBasicCSVParser::parse_field() noexcept - { + CSV_INLINE void IBasicCSVParser::parse_field() noexcept { using internals::ParseFlags; auto& in = this->data_ptr->data; @@ -7235,14 +6956,20 @@ namespace csv CSV_INLINE void IBasicCSVParser::push_field() { // Update - if (field_has_double_quote) - { - fields->emplace_back(field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, field_length, true); + if (field_has_double_quote) { + fields->emplace_back( + field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, + field_length, + true + ); field_has_double_quote = false; + } - else - { - fields->emplace_back(field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, field_length); + else { + fields->emplace_back( + field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start, + field_length + ); } current_row.row_length++; @@ -7263,10 +6990,8 @@ namespace csv this->trim_utf8_bom(); auto& in = this->data_ptr->data; - while (this->data_pos < in.size()) - { - switch (compound_parse_flag(in[this->data_pos])) - { + while (this->data_pos < in.size()) { + switch (compound_parse_flag(in[this->data_pos])) { case ParseFlags::DELIMITER: this->push_field(); this->data_pos++; @@ -7292,19 +7017,15 @@ namespace csv break; case ParseFlags::QUOTE_ESCAPE_QUOTE: - if (data_pos + 1 == in.size()) - return this->current_row_start(); - else if (data_pos + 1 < in.size()) - { + if (data_pos + 1 == in.size()) return this->current_row_start(); + else if (data_pos + 1 < in.size()) { auto next_ch = parse_flag(in[data_pos + 1]); - if (next_ch >= ParseFlags::DELIMITER) - { + if (next_ch >= ParseFlags::DELIMITER) { quote_escape = false; data_pos++; break; } - else if (next_ch == ParseFlags::QUOTE) - { + else if (next_ch == ParseFlags::QUOTE) { // Case: Escaped quote data_pos += 2; this->field_length += 2; @@ -7312,7 +7033,7 @@ namespace csv break; } } - + // Case: Unescaped single quote => not strictly valid but we'll keep it this->field_length++; data_pos++; @@ -7320,8 +7041,7 @@ namespace csv break; default: // Quote (currently not quote escaped) - if (this->field_length == 0) - { + if (this->field_length == 0) { quote_escape = true; data_pos++; if (field_start == UNINITIALIZED_FIELD && data_pos < in.size() && !ws_flag(in[data_pos])) @@ -7340,28 +7060,23 @@ namespace csv return this->current_row_start(); } - CSV_INLINE void IBasicCSVParser::push_row() - { + CSV_INLINE void IBasicCSVParser::push_row() { current_row.row_length = fields->size() - current_row.fields_start; this->_records->push_back(std::move(current_row)); } - CSV_INLINE void IBasicCSVParser::reset_data_ptr() - { + CSV_INLINE void IBasicCSVParser::reset_data_ptr() { this->data_ptr = std::make_shared(); this->data_ptr->parse_flags = this->_parse_flags; this->data_ptr->col_names = this->_col_names; this->fields = &(this->data_ptr->fields); } - CSV_INLINE void IBasicCSVParser::trim_utf8_bom() - { + CSV_INLINE void IBasicCSVParser::trim_utf8_bom() { auto& data = this->data_ptr->data; - if (!this->unicode_bom_scan && data.size() >= 3) - { - if (data[0] == '\xEF' && data[1] == '\xBB' && data[2] == '\xBF') - { + if (!this->unicode_bom_scan && data.size() >= 3) { + if (data[0] == '\xEF' && data[1] == '\xBB' && data[2] == '\xBF') { this->data_pos += 3; // Remove BOM from input string this->_utf8_bom = true; } @@ -7376,8 +7091,7 @@ namespace csv #ifdef _MSC_VER #pragma region Specializations #endif - CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) - { + CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) { // Reset parser state this->field_start = UNINITIALIZED_FIELD; this->field_length = 0; @@ -7386,11 +7100,9 @@ namespace csv // Create memory map size_t length = std::min(this->source_size - this->mmap_pos, bytes); std::error_code error; - this->data_ptr->_data = - std::make_shared>(mio::make_mmap_source(this->_filename, this->mmap_pos, length, error)); + this->data_ptr->_data = std::make_shared>(mio::make_mmap_source(this->_filename, this->mmap_pos, length, error)); this->mmap_pos += length; - if (error) - throw error; + if (error) throw error; auto mmap_ptr = (mio::basic_mmap_source*)(this->data_ptr->_data.get()); @@ -7399,10 +7111,9 @@ namespace csv // Parse this->current_row = CSVRow(this->data_ptr); - size_t remainder = this->parse(); + size_t remainder = this->parse(); - if (this->mmap_pos == this->source_size || no_chunk()) - { + if (this->mmap_pos == this->source_size || no_chunk()) { this->_eof = true; this->end_feed(); } @@ -7412,30 +7123,25 @@ namespace csv #ifdef _MSC_VER #pragma endregion #endif - } // namespace internals -} // namespace csv + } +} -namespace csv -{ - namespace internals - { - CSV_INLINE std::vector ColNames::get_col_names() const - { + +namespace csv { + namespace internals { + CSV_INLINE std::vector ColNames::get_col_names() const { return this->col_names; } - CSV_INLINE void ColNames::set_col_names(const std::vector& cnames) - { + CSV_INLINE void ColNames::set_col_names(const std::vector& cnames) { this->col_names = cnames; - for (size_t i = 0; i < cnames.size(); i++) - { + for (size_t i = 0; i < cnames.size(); i++) { this->col_pos[cnames[i]] = i; } } - CSV_INLINE int ColNames::index_of(csv::string_view col_name) const - { + CSV_INLINE int ColNames::index_of(csv::string_view col_name) const { auto pos = this->col_pos.find(col_name.data()); if (pos != this->col_pos.end()) return (int)pos->second; @@ -7443,13 +7149,12 @@ namespace csv return CSV_NOT_FOUND; } - CSV_INLINE size_t ColNames::size() const noexcept - { + CSV_INLINE size_t ColNames::size() const noexcept { return this->col_names.size(); } - } // namespace internals -} // namespace csv + } +} /** @file * Defines an object used to store CSV format settings */ @@ -7457,48 +7162,41 @@ namespace csv #include #include -namespace csv -{ - CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) - { + +namespace csv { + CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) { this->possible_delimiters = { delim }; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector& delim) - { + CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector & delim) { this->possible_delimiters = delim; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::quote(char quote) - { + CSV_INLINE CSVFormat& CSVFormat::quote(char quote) { this->no_quote = false; this->quote_char = quote; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector& chars) - { + CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector & chars) { this->trim_chars = chars; this->assert_no_char_overlap(); return *this; } - CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector& names) - { + CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector& names) { this->col_names = names; this->header = -1; return *this; } - CSV_INLINE CSVFormat& CSVFormat::header_row(int row) - { - if (row < 0) - this->variable_column_policy = VariableColumnPolicy::KEEP; + CSV_INLINE CSVFormat& CSVFormat::header_row(int row) { + if (row < 0) this->variable_column_policy = VariableColumnPolicy::KEEP; this->header = row; this->col_names = {}; @@ -7507,32 +7205,35 @@ namespace csv CSV_INLINE void CSVFormat::assert_no_char_overlap() { - auto delims = std::set(this->possible_delimiters.begin(), this->possible_delimiters.end()), - trims = std::set(this->trim_chars.begin(), this->trim_chars.end()); + auto delims = std::set( + this->possible_delimiters.begin(), this->possible_delimiters.end()), + trims = std::set( + this->trim_chars.begin(), this->trim_chars.end()); // Stores intersection of possible delimiters and trim characters std::vector intersection = {}; // Find which characters overlap, if any - std::set_intersection(delims.begin(), delims.end(), trims.begin(), trims.end(), std::back_inserter(intersection)); + std::set_intersection( + delims.begin(), delims.end(), + trims.begin(), trims.end(), + std::back_inserter(intersection)); // Make sure quote character is not contained in possible delimiters // or whitespace characters - if (delims.find(this->quote_char) != delims.end() || trims.find(this->quote_char) != trims.end()) - { + if (delims.find(this->quote_char) != delims.end() || + trims.find(this->quote_char) != trims.end()) { intersection.push_back(this->quote_char); } - if (!intersection.empty()) - { + if (!intersection.empty()) { std::string err_msg = "There should be no overlap between the quote character, " - "the set of possible delimiters " - "and the set of whitespace characters. Offending characters: "; + "the set of possible delimiters " + "and the set of whitespace characters. Offending characters: "; // Create a pretty error message with the list of overlapping // characters - for (size_t i = 0; i < intersection.size(); i++) - { + for (size_t i = 0; i < intersection.size(); i++) { err_msg += "'"; err_msg += intersection[i]; err_msg += "'"; @@ -7544,26 +7245,21 @@ namespace csv throw std::runtime_error(err_msg + '.'); } } -} // namespace csv +} /** @file * @brief Defines functionality needed for basic CSV parsing */ -namespace csv -{ - namespace internals - { - CSV_INLINE std::string format_row(const std::vector& row, csv::string_view delim) - { + +namespace csv { + namespace internals { + CSV_INLINE std::string format_row(const std::vector& row, csv::string_view delim) { /** Print a CSV row */ std::stringstream ret; - for (size_t i = 0; i < row.size(); i++) - { + for (size_t i = 0; i < row.size(); i++) { ret << row[i]; - if (i + 1 < row.size()) - ret << delim; - else - ret << '\n'; + if (i + 1 < row.size()) ret << delim; + else ret << '\n'; } ret.flush(); @@ -7576,8 +7272,7 @@ namespace csv * @param[in] format Format of the CSV file * */ - CSV_INLINE std::vector _get_col_names(csv::string_view head, CSVFormat format) - { + CSV_INLINE std::vector _get_col_names(csv::string_view head, CSVFormat format) { // Parse the CSV auto trim_chars = format.get_trim_chars(); std::stringstream source(head.data()); @@ -7590,8 +7285,7 @@ namespace csv return CSVRow(std::move(rows[format.get_header()])); } - CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format) - { + CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format) { // Frequency counter of row length std::unordered_map row_tally = { { 0, 0 } }; @@ -7606,19 +7300,15 @@ namespace csv parser.set_output(rows); parser.next(); - for (size_t i = 0; i < rows.size(); i++) - { + for (size_t i = 0; i < rows.size(); i++) { auto& row = rows[i]; // Ignore zero-length rows - if (row.size() > 0) - { - if (row_tally.find(row.size()) != row_tally.end()) - { + if (row.size() > 0) { + if (row_tally.find(row.size()) != row_tally.end()) { row_tally[row.size()]++; } - else - { + else { row_tally[row.size()] = 1; row_when[row.size()] = i; } @@ -7630,24 +7320,24 @@ namespace csv // Final score is equal to the largest // row size times rows of that size - for (auto& pair : row_tally) - { + for (auto& pair : row_tally) { auto row_size = pair.first; auto row_count = pair.second; double score = (double)(row_size * row_count); - if (score > final_score) - { + if (score > final_score) { final_score = score; header_row = row_when[row_size]; } } - return { final_score, header_row }; + return { + final_score, + header_row + }; } /** Guess the delimiter used by a delimiter-separated values file */ - CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims) - { + CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector& delims) { /** For each delimiter, find out which row length was most common. * The delimiter with the longest mode row length wins. * Then, the line number of the header row is the first row with @@ -7655,15 +7345,14 @@ namespace csv */ CSVFormat format; - size_t max_score = 0, header = 0; + size_t max_score = 0, + header = 0; char current_delim = delims[0]; - for (char cand_delim : delims) - { + for (char cand_delim : delims) { auto result = calculate_score(head, format.delimiter(cand_delim)); - if ((size_t)result.score > max_score) - { + if ((size_t)result.score > max_score) { max_score = (size_t)result.score; current_delim = cand_delim; header = result.header; @@ -7672,7 +7361,7 @@ namespace csv return { current_delim, (int)header }; } - } // namespace internals + } /** Return a CSV's column names * @@ -7680,13 +7369,11 @@ namespace csv * @param[in] format Format of the CSV file * */ - CSV_INLINE std::vector get_col_names(csv::string_view filename, CSVFormat format) - { + CSV_INLINE std::vector get_col_names(csv::string_view filename, CSVFormat format) { auto head = internals::get_csv_head(filename); /** Guess delimiter and header row */ - if (format.guess_delim()) - { + if (format.guess_delim()) { auto guess_result = guess_format(filename, format.get_possible_delims()); format.delimiter(guess_result.delim).header_row(guess_result.header_row); } @@ -7695,8 +7382,7 @@ namespace csv } /** Guess the delimiter used by a delimiter-separated values file */ - CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims) - { + CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector& delims) { auto head = internals::get_csv_head(filename); return internals::_guess_format(head, delims); } @@ -7712,15 +7398,12 @@ namespace csv * \snippet tests/test_read_csv.cpp CSVField Example * */ - CSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) - : _format(format) - { + CSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) : _format(format) { auto head = internals::get_csv_head(filename); using Parser = internals::MmapParser; /** Guess delimiter and header row */ - if (format.guess_delim()) - { + if (format.guess_delim()) { auto guess_result = internals::_guess_format(head, format.possible_delimiters); format.delimiter(guess_result.delim); format.header = guess_result.header_row; @@ -7735,8 +7418,7 @@ namespace csv } /** Return the format of the original raw CSV */ - CSV_INLINE CSVFormat CSVReader::get_format() const - { + CSV_INLINE CSVFormat CSVReader::get_format() const { CSVFormat new_format = this->_format; // Since users are normally not allowed to set @@ -7749,10 +7431,8 @@ namespace csv } /** Return the CSV's column names as a vector of strings. */ - CSV_INLINE std::vector CSVReader::get_col_names() const - { - if (this->col_names) - { + CSV_INLINE std::vector CSVReader::get_col_names() const { + if (this->col_names) { return this->col_names->get_col_names(); } @@ -7762,28 +7442,21 @@ namespace csv /** Return the index of the column name if found or * csv::CSV_NOT_FOUND otherwise. */ - CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const - { + CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const { auto _col_names = this->get_col_names(); for (size_t i = 0; i < _col_names.size(); i++) - if (_col_names[i] == col_name) - return (int)i; + if (_col_names[i] == col_name) return (int)i; return CSV_NOT_FOUND; } - CSV_INLINE void CSVReader::trim_header() - { - if (!this->header_trimmed) - { - for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) - { - if (i == this->_format.header && this->col_names->empty()) - { + CSV_INLINE void CSVReader::trim_header() { + if (!this->header_trimmed) { + for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) { + if (i == this->_format.header && this->col_names->empty()) { this->set_col_names(this->records->pop_front()); } - else - { + else { this->records->pop_front(); } } @@ -7812,16 +7485,14 @@ namespace csv * @see CSVReader::read_csv_worker * @see CSVReader::read_row() */ - CSV_INLINE bool CSVReader::read_csv(size_t bytes) - { + CSV_INLINE bool CSVReader::read_csv(size_t bytes) { // Tell read_row() to listen for CSV rows this->records->notify_all(); this->parser->set_output(*this->records); this->parser->next(bytes); - if (!this->header_trimmed) - { + if (!this->header_trimmed) { this->trim_header(); } @@ -7845,20 +7516,16 @@ namespace csv * \snippet tests/test_read_csv.cpp CSVField Example * */ - CSV_INLINE bool CSVReader::read_row(CSVRow& row) - { - while (true) - { - if (this->records->empty()) - { + CSV_INLINE bool CSVReader::read_row(CSVRow &row) { + while (true) { + if (this->records->empty()) { if (this->records->is_waitable()) // Reading thread is currently active => wait for it to populate records this->records->wait(); else if (this->parser->eof()) // End of file and no more records return false; - else - { + else { // Reading thread is not active => start another one if (this->read_csv_worker.joinable()) this->read_csv_worker.join(); @@ -7866,20 +7533,18 @@ namespace csv this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); } } - else if (this->records->front().size() != this->n_cols && this->_format.variable_column_policy != VariableColumnPolicy::KEEP) - { + else if (this->records->front().size() != this->n_cols && + this->_format.variable_column_policy != VariableColumnPolicy::KEEP) { auto errored_row = this->records->pop_front(); - if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) - { + if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) { if (errored_row.size() < this->n_cols) throw std::runtime_error("Line too short " + internals::format_row(errored_row)); throw std::runtime_error("Line too long " + internals::format_row(errored_row)); } } - else - { + else { row = this->records->pop_front(); this->_n_rows++; return true; @@ -7888,25 +7553,22 @@ namespace csv return false; } -} // namespace csv +} /** @file * Defines an input iterator for csv::CSVReader */ -namespace csv -{ + +namespace csv { /** Return an iterator to the first row in the reader */ - CSV_INLINE CSVReader::iterator CSVReader::begin() - { - if (this->records->empty()) - { + CSV_INLINE CSVReader::iterator CSVReader::begin() { + if (this->records->empty()) { this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE); this->read_csv_worker.join(); // Still empty => return end iterator - if (this->records->empty()) - return this->end(); + if (this->records->empty()) return this->end(); } CSVReader::iterator ret(this, this->records->pop_front()); @@ -7916,8 +7578,7 @@ namespace csv /** A placeholder for the imaginary past the end row in a CSV. * Attempting to deference this will lead to bad things. */ - CSV_INLINE HEDLEY_CONST CSVReader::iterator CSVReader::end() const noexcept - { + CSV_INLINE HEDLEY_CONST CSVReader::iterator CSVReader::end() const noexcept { return CSVReader::iterator(); } @@ -7925,9 +7586,8 @@ namespace csv // CSVReader::iterator // ///////////////////////// - CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) - : daddy(_daddy) - { + CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) : + daddy(_daddy) { row = std::move(_row); } @@ -7938,10 +7598,8 @@ namespace csv * @note This iterator does **not** block the thread responsible for parsing CSV. * */ - CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() - { - if (!daddy->read_row(this->row)) - { + CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() { + if (!daddy->read_row(this->row)) { this->daddy = nullptr; // this == end() } @@ -7949,17 +7607,15 @@ namespace csv } /** Post-increment iterator */ - CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) - { + CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) { auto temp = *this; - if (!daddy->read_row(this->row)) - { + if (!daddy->read_row(this->row)) { this->daddy = nullptr; // this == end() } return temp; } -} // namespace csv +} /** @file * Defines the data type used for storing information about a CSV row @@ -7968,25 +7624,21 @@ namespace csv #include #include -namespace csv -{ - namespace internals - { - CSV_INLINE RawCSVField& CSVFieldList::operator[](size_t n) const - { +namespace csv { + namespace internals { + CSV_INLINE RawCSVField& CSVFieldList::operator[](size_t n) const { const size_t page_no = n / _single_buffer_capacity; const size_t buffer_idx = (page_no < 1) ? n : n % _single_buffer_capacity; return this->buffers[page_no][buffer_idx]; } - CSV_INLINE void CSVFieldList::allocate() - { - RawCSVField* buffer = new RawCSVField[_single_buffer_capacity]; + CSV_INLINE void CSVFieldList::allocate() { + RawCSVField * buffer = new RawCSVField[_single_buffer_capacity]; buffers.push_back(buffer); _current_buffer_size = 0; _back = &(buffers.back()[0]); } - } // namespace internals + } /** Return a CSVField object corrsponding to the nth value in the row. * @@ -7997,8 +7649,7 @@ namespace csv * Constant, by calling csv::CSVRow::get_csv::string_view() * */ - CSV_INLINE CSVField CSVRow::operator[](size_t n) const - { + CSV_INLINE CSVField CSVRow::operator[](size_t n) const { return CSVField(this->get_field(n)); } @@ -8011,20 +7662,17 @@ namespace csv * * @param[in] col_name The column to look for */ - CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const - { - auto& col_names = this->data->col_names; + CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const { + auto & col_names = this->data->col_names; auto col_pos = col_names->index_of(col_name); - if (col_pos > -1) - { + if (col_pos > -1) { return this->operator[](col_pos); } throw std::runtime_error("Can't find a column named " + col_name); } - CSV_INLINE CSVRow::operator std::vector() const - { + CSV_INLINE CSVRow::operator std::vector() const { std::vector ret; for (size_t i = 0; i < size(); i++) ret.push_back(std::string(this->get_field(i))); @@ -8043,23 +7691,17 @@ namespace csv auto& field = this->data->fields[field_index]; auto field_str = csv::string_view(this->data->data).substr(this->data_start + field.start); - if (field.has_double_quote) - { + if (field.has_double_quote) { auto& value = this->data->double_quote_fields[field_index]; - if (value.empty()) - { + if (value.empty()) { bool prev_ch_quote = false; - for (size_t i = 0; i < field.length; i++) - { - if (this->data->parse_flags[field_str[i] + 128] == ParseFlags::QUOTE) - { - if (prev_ch_quote) - { + for (size_t i = 0; i < field.length; i++) { + if (this->data->parse_flags[field_str[i] + 128] == ParseFlags::QUOTE) { + if (prev_ch_quote) { prev_ch_quote = false; continue; } - else - { + else { prev_ch_quote = true; } } @@ -8074,30 +7716,24 @@ namespace csv return field_str.substr(0, field.length); } - CSV_INLINE bool CSVField::try_parse_hex(int& parsedValue) - { + CSV_INLINE bool CSVField::try_parse_hex(int& parsedValue) { size_t start = 0, end = 0; // Trim out whitespace chars - for (; start < this->sv.size() && this->sv[start] == ' '; start++) - ; - for (end = start; end < this->sv.size() && this->sv[end] != ' '; end++) - ; - + for (; start < this->sv.size() && this->sv[start] == ' '; start++); + for (end = start; end < this->sv.size() && this->sv[end] != ' '; end++); + unsigned long long int value = 0; size_t digits = (end - start); size_t base16_exponent = digits - 1; - if (digits == 0) - return false; + if (digits == 0) return false; - for (const auto& ch : this->sv.substr(start, digits)) - { + for (const auto& ch : this->sv.substr(start, digits)) { int digit = 0; - switch (ch) - { + switch (ch) { case '0': case '1': case '2': @@ -8150,8 +7786,7 @@ namespace csv #pragma region CSVRow Iterator #endif /** Return an iterator pointing to the first field. */ - CSV_INLINE CSVRow::iterator CSVRow::begin() const - { + CSV_INLINE CSVRow::iterator CSVRow::begin() const { return CSVRow::iterator(this, 0); } @@ -8160,103 +7795,94 @@ namespace csv * @warning Attempting to dereference the end iterator results * in dereferencing a null pointer. */ - CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept - { + CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept { return CSVRow::iterator(this, (int)this->size()); } - CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept - { + CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept { return std::reverse_iterator(this->end()); } - CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const - { + CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const { return std::reverse_iterator(this->begin()); } - CSV_INLINE HEDLEY_NON_NULL(2) CSVRow::iterator::iterator(const CSVRow* _reader, int _i) - : daddy(_reader) - , i(_i) - { + CSV_INLINE HEDLEY_NON_NULL(2) + CSVRow::iterator::iterator(const CSVRow* _reader, int _i) + : daddy(_reader), i(_i) { if (_i < (int)this->daddy->size()) - this->field = std::make_shared(this->daddy->operator[](_i)); + this->field = std::make_shared( + this->daddy->operator[](_i)); else this->field = nullptr; } - CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const - { + CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const { return *(this->field.get()); } - CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const - { -// Using CSVField * as pointer type causes segfaults in MSVC debug builds -#ifdef _MSC_BUILD + CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const { + // Using CSVField * as pointer type causes segfaults in MSVC debug builds + #ifdef _MSC_BUILD return this->field; -#else + #else return this->field.get(); -#endif + #endif } - CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() - { + CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() { // Pre-increment operator this->i++; if (this->i < (int)this->daddy->size()) - this->field = std::make_shared(this->daddy->operator[](i)); + this->field = std::make_shared( + this->daddy->operator[](i)); else // Reached the end of row this->field = nullptr; return *this; } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) - { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) { // Post-increment operator auto temp = *this; this->operator++(); return temp; } - CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() - { + CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() { // Pre-decrement operator this->i--; - this->field = std::make_shared(this->daddy->operator[](this->i)); + this->field = std::make_shared( + this->daddy->operator[](this->i)); return *this; } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) - { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) { // Post-decrement operator auto temp = *this; this->operator--(); return temp; } - - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const - { + + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const { // Allows for iterator arithmetic return CSVRow::iterator(this->daddy, i + (int)n); } - CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const - { + CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const { // Allows for iterator arithmetic return CSVRow::iterator::operator+(-n); } #ifdef _MSC_VER #pragma endregion CSVRow Iterator #endif -} // namespace csv +} /** @file * Implements JSON serialization abilities */ -namespace csv -{ + +namespace csv { /* The implementations for json_extra_space() and json_escape_string() were modified from source code for JSON for Modern C++. @@ -8265,9 +7891,9 @@ namespace csv The code is licensed under the [MIT License](http://opensource.org/licenses/MIT): - + Copyright © 2013-2015 Niels Lohmann. - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, @@ -8275,10 +7901,10 @@ namespace csv publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -8289,8 +7915,7 @@ namespace csv SOFTWARE. */ - namespace internals - { + namespace internals { /*! @brief calculates the extra space to escape a JSON string @@ -8303,6 +7928,7 @@ namespace csv { std::size_t result = 0; + for (const auto& c : s) { switch (c) @@ -8314,24 +7940,26 @@ namespace csv case '\n': case '\r': case '\t': - { - // from c (1 byte) to \x (2 bytes) - result += 1; - break; - } + { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } + default: + { + if (c >= 0x00 && c <= 0x1f) { - if (c >= 0x00 && c <= 0x1f) - { - // from c (1 byte) to \uxxxx (6 bytes) - result += 5; - } - break; + // from c (1 byte) to \uxxxx (6 bytes) + result += 5; } + break; + } } } + return result; } @@ -8353,83 +7981,90 @@ namespace csv { // quotation mark (0x22) case '"': - { - result[pos + 1] = '"'; - pos += 2; - break; - } + { + result[pos + 1] = '"'; + pos += 2; + break; + } + // reverse solidus (0x5c) case '\\': - { - // nothing to change - pos += 2; - break; - } + { + // nothing to change + pos += 2; + break; + } + // backspace (0x08) case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + // formfeed (0x0c) case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + // newline (0x0a) case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + // carriage return (0x0d) case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + // horizontal tab (0x09) case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } + { + result[pos + 1] = 't'; + pos += 2; + break; + } + default: + { + if (c >= 0x00 && c <= 0x1f) { - if (c >= 0x00 && c <= 0x1f) - { - // print character c as \uxxxx - sprintf(&result[pos + 1], "u%04x", int(c)); - pos += 6; - // overwrite trailing null character - result[pos] = '\\'; - } - else - { - // all other characters are added as-is - result[pos++] = c; - } - break; + // print character c as \uxxxx + sprintf(&result[pos + 1], "u%04x", int(c)); + pos += 6; + // overwrite trailing null character + result[pos] = '\\'; + } + else + { + // all other characters are added as-is + result[pos++] = c; } + break; + } } } return result; } - } // namespace internals + } /** Convert a CSV row to a JSON object, i.e. * `{"col1":"value1","col2":"value2"}` @@ -8438,19 +8073,16 @@ namespace csv * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for original columns. */ - CSV_INLINE std::string CSVRow::to_json(const std::vector& subset) const - { + CSV_INLINE std::string CSVRow::to_json(const std::vector& subset) const { std::vector col_names = subset; - if (subset.empty()) - { + if (subset.empty()) { col_names = this->data ? this->get_col_names() : std::vector({}); } const size_t _n_cols = col_names.size(); std::string ret = "{"; - - for (size_t i = 0; i < _n_cols; i++) - { + + for (size_t i = 0; i < _n_cols; i++) { auto& col = col_names[i]; auto field = this->operator[](col); @@ -8459,7 +8091,7 @@ namespace csv // Add quotes around strings but not numbers if (field.is_num()) - ret += internals::json_escape_string(field.get()); + ret += internals::json_escape_string(field.get()); else ret += '"' + internals::json_escape_string(field.get()) + '"'; @@ -8479,8 +8111,7 @@ namespace csv * @param[in] subset A subset of columns to contain in the JSON. * Leave empty for all columns. */ - CSV_INLINE std::string CSVRow::to_json_array(const std::vector& subset) const - { + CSV_INLINE std::string CSVRow::to_json_array(const std::vector& subset) const { std::vector col_names = subset; if (subset.empty()) col_names = this->data ? this->get_col_names() : std::vector({}); @@ -8488,8 +8119,7 @@ namespace csv const size_t _n_cols = col_names.size(); std::string ret = "["; - for (size_t i = 0; i < _n_cols; i++) - { + for (size_t i = 0; i < _n_cols; i++) { auto field = this->operator[](col_names[i]); // Add quotes around strings but not numbers @@ -8506,106 +8136,88 @@ namespace csv ret += ']'; return ret; } -} // namespace csv +} /** @file * Calculates statistics from CSV files */ #include -namespace csv -{ +namespace csv { /** Calculate statistics for an arbitrarily large file. When this constructor * is called, CSVStat will process the entire file iteratively. Once finished, * methods like get_mean(), get_counts(), etc... can be used to retrieve statistics. */ - CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) - : reader(filename, format) - { + CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) : + reader(filename, format) { this->calc(); } /** Calculate statistics for a CSV stored in a std::stringstream */ - CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) - : reader(stream, format) - { + CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) : + reader(stream, format) { this->calc(); } /** Return current means */ - CSV_INLINE std::vector CSVStat::get_mean() const - { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + CSV_INLINE std::vector CSVStat::get_mean() const { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->rolling_means[i]); } return ret; } /** Return current variances */ - CSV_INLINE std::vector CSVStat::get_variance() const - { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { - ret.push_back(this->rolling_vars[i] / (this->n[i] - 1)); + CSV_INLINE std::vector CSVStat::get_variance() const { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) { + ret.push_back(this->rolling_vars[i]/(this->n[i] - 1)); } return ret; } /** Return current mins */ - CSV_INLINE std::vector CSVStat::get_mins() const - { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + CSV_INLINE std::vector CSVStat::get_mins() const { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->mins[i]); } return ret; } /** Return current maxes */ - CSV_INLINE std::vector CSVStat::get_maxes() const - { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + CSV_INLINE std::vector CSVStat::get_maxes() const { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->maxes[i]); } return ret; } /** Get counts for each column */ - CSV_INLINE std::vector CSVStat::get_counts() const - { + CSV_INLINE std::vector CSVStat::get_counts() const { std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->counts[i]); } return ret; } /** Get data type counts for each column */ - CSV_INLINE std::vector CSVStat::get_dtypes() const - { - std::vector ret; - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + CSV_INLINE std::vector CSVStat::get_dtypes() const { + std::vector ret; + for (size_t i = 0; i < this->get_col_names().size(); i++) { ret.push_back(this->dtypes[i]); } return ret; } - CSV_INLINE void CSVStat::calc_chunk() - { + CSV_INLINE void CSVStat::calc_chunk() { /** Only create stats counters the first time **/ - if (dtypes.empty()) - { + if (dtypes.empty()) { /** Go through all records and calculate specified statistics */ - for (size_t i = 0; i < this->get_col_names().size(); i++) - { + for (size_t i = 0; i < this->get_col_names().size(); i++) { dtypes.push_back({}); counts.push_back({}); rolling_means.push_back(0); @@ -8628,40 +8240,33 @@ namespace csv this->records.clear(); } - CSV_INLINE void CSVStat::calc() - { + CSV_INLINE void CSVStat::calc() { constexpr size_t CALC_CHUNK_SIZE = 5000; - for (auto& row : reader) - { + for (auto& row : reader) { this->records.push_back(std::move(row)); /** Chunk rows */ - if (this->records.size() == CALC_CHUNK_SIZE) - { + if (this->records.size() == CALC_CHUNK_SIZE) { calc_chunk(); } } - if (!this->records.empty()) - { - calc_chunk(); + if (!this->records.empty()) { + calc_chunk(); } } - CSV_INLINE void CSVStat::calc_worker(const size_t& i) - { + CSV_INLINE void CSVStat::calc_worker(const size_t &i) { /** Worker thread for CSVStat::calc() which calculates statistics for one column. - * + * * @param[in] i Column index */ auto current_record = this->records.begin(); - for (size_t processed = 0; current_record != this->records.end(); processed++) - { - if (current_record->size() == this->get_col_names().size()) - { + for (size_t processed = 0; current_record != this->records.end(); processed++) { + if (current_record->size() == this->get_col_names().size()) { auto current_field = (*current_record)[i]; // Optimization: Don't count() if there's too many distinct values in the first 1000 rows @@ -8671,8 +8276,7 @@ namespace csv this->dtype(current_field, i); // Numeric Stuff - if (current_field.is_num()) - { + if (current_field.is_num()) { long double x_n = current_field.get(); // This actually calculates mean AND variance @@ -8680,8 +8284,7 @@ namespace csv this->min_max(x_n, i); } } - else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) - { + else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) { throw std::runtime_error("Line has different length than the others " + internals::format_row(*current_record)); } @@ -8689,28 +8292,24 @@ namespace csv } } - CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t& i) - { + CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t &i) { /** Given a record update the type counter * @param[in] record Data observation * @param[out] i The column index that should be updated */ - + auto type = data.type(); - if (this->dtypes[i].find(type) != this->dtypes[i].end()) - { + if (this->dtypes[i].find(type) != + this->dtypes[i].end()) { // Increment count this->dtypes[i][type]++; - } - else - { + } else { // Initialize count this->dtypes[i].insert(std::make_pair(type, 1)); } } - CSV_INLINE void CSVStat::count(CSVField& data, const size_t& i) - { + CSV_INLINE void CSVStat::count(CSVField& data, const size_t &i) { /** Given a record update the frequency counter * @param[in] record Data observation * @param[out] i The column index that should be updated @@ -8718,20 +8317,17 @@ namespace csv auto item = data.get(); - if (this->counts[i].find(item) != this->counts[i].end()) - { + if (this->counts[i].find(item) != + this->counts[i].end()) { // Increment count this->counts[i][item]++; - } - else - { + } else { // Initialize count this->counts[i].insert(std::make_pair(item, 1)); } } - CSV_INLINE void CSVStat::min_max(const long double& x_n, const size_t& i) - { + CSV_INLINE void CSVStat::min_max(const long double &x_n, const size_t &i) { /** Update current minimum and maximum * @param[in] x_n Data observation * @param[out] i The column index that should be updated @@ -8740,15 +8336,14 @@ namespace csv this->mins[i] = x_n; if (std::isnan(this->maxes[i])) this->maxes[i] = x_n; - + if (x_n < this->mins[i]) this->mins[i] = x_n; else if (x_n > this->maxes[i]) this->maxes[i] = x_n; } - CSV_INLINE void CSVStat::variance(const long double& x_n, const size_t& i) - { + CSV_INLINE void CSVStat::variance(const long double &x_n, const size_t &i) { /** Given a record update rolling mean and variance for all columns * using Welford's Algorithm * @param[in] x_n Data observation @@ -8761,17 +8356,14 @@ namespace csv long double delta2; current_n++; - - if (current_n == 1) - { + + if (current_n == 1) { current_rolling_mean = x_n; - } - else - { + } else { delta = x_n - current_rolling_mean; - current_rolling_mean += delta / current_n; + current_rolling_mean += delta/current_n; delta2 = x_n - current_rolling_mean; - current_rolling_var += delta * delta2; + current_rolling_var += delta*delta2; } } @@ -8783,16 +8375,14 @@ namespace csv * * \return A mapping of column names to csv::DataType enums */ - CSV_INLINE std::unordered_map csv_data_types(const std::string& filename) - { + CSV_INLINE std::unordered_map csv_data_types(const std::string& filename) { CSVStat stat(filename); std::unordered_map csv_dtypes; auto col_names = stat.get_col_names(); auto temp = stat.get_dtypes(); - for (size_t i = 0; i < stat.get_col_names().size(); i++) - { + for (size_t i = 0; i < stat.get_col_names().size(); i++) { auto& col = temp[i]; auto& col_name = col_names[i]; @@ -8812,12 +8402,12 @@ namespace csv return csv_dtypes; } -} // namespace csv +} #include #include -namespace csv -{ + +namespace csv { /** Shorthand function for parsing an in-memory CSV string * * @return A collection of CSVRow objects @@ -8825,8 +8415,7 @@ namespace csv * @par Example * @snippet tests/test_read_csv.cpp Parse Example */ - CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) - { + CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) { std::stringstream stream(in.data()); return CSVReader(stream, format); } @@ -8835,8 +8424,7 @@ namespace csv * * @return A collection of CSVRow objects */ - CSV_INLINE CSVReader parse_no_header(csv::string_view in) - { + CSV_INLINE CSVReader parse_no_header(csv::string_view in) { CSVFormat format; format.header_row(-1); @@ -8850,14 +8438,12 @@ namespace csv * @snippet tests/test_read_csv.cpp Escaped Comma * */ - CSV_INLINE CSVReader operator""_csv(const char* in, size_t n) - { + CSV_INLINE CSVReader operator ""_csv(const char* in, size_t n) { return parse(csv::string_view(in, n)); } /** A shorthand for csv::parse_no_header() */ - CSV_INLINE CSVReader operator""_csv_no_header(const char* in, size_t n) - { + CSV_INLINE CSVReader operator ""_csv_no_header(const char* in, size_t n) { return parse_no_header(csv::string_view(in, n)); } @@ -8868,8 +8454,10 @@ namespace csv * @param[in] col_name Column whose position we should resolve * @param[in] format Format of the CSV file */ - CSV_INLINE int get_col_pos(csv::string_view filename, csv::string_view col_name, const CSVFormat& format) - { + CSV_INLINE int get_col_pos( + csv::string_view filename, + csv::string_view col_name, + const CSVFormat& format) { CSVReader reader(filename, format); return reader.index_of(col_name); } @@ -8877,17 +8465,22 @@ namespace csv /** Get basic information about a CSV file * @include programs/csv_info.cpp */ - CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) - { + CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) { CSVReader reader(filename); CSVFormat format = reader.get_format(); - for (auto it = reader.begin(); it != reader.end(); ++it) - ; - - CSVFileInfo info = { filename, reader.get_col_names(), format.get_delim(), reader.n_rows(), reader.get_col_names().size() }; + for (auto it = reader.begin(); it != reader.end(); ++it); + + CSVFileInfo info = { + filename, + reader.get_col_names(), + format.get_delim(), + reader.n_rows(), + reader.get_col_names().size() + }; return info; } -} // namespace csv +} + #endif From 687aff9a251ed936d10b7f6e642b20a518a15dc5 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 12:52:39 +0200 Subject: [PATCH 42/47] add counter to track if all entities are spawned Signed-off-by: Wojciech Czerski --- .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 88e79425..082a035d 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -252,6 +252,10 @@ namespace CsvSpawner::CsvSpawnerUtils } } + // Track how many tickets are spawned and how many have completed + size_t totalTickets = 0; + std::atomic_size_t completedTickets = 0; + for (const auto& entityConfig : entitiesToSpawn) { if (!spawnableAssetConfiguration.contains(entityConfig.m_name)) @@ -317,7 +321,7 @@ namespace CsvSpawner::CsvSpawnerUtils transformInterface->SetWorldTM(transform); }; optionalArgs.m_completionCallback = - [parentId, &spawnStatusCode]( + [parentId, &spawnStatusCode, &broadcastSpawnInfo, &tickets, totalTickets, &completedTickets]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) { if (view.empty()) @@ -329,16 +333,28 @@ namespace CsvSpawner::CsvSpawnerUtils } const AZ::Entity* root = *view.begin(); AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); + + completedTickets++; + if (completedTickets == totalTickets) + { + // Call CsvSpawner EBus notification - Finished + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); + } }; optionalArgs.m_priority = AzFramework::SpawnablePriority_Lowest; spawner->SpawnAllEntities(ticket, optionalArgs); tickets[entityConfig.m_id] = AZStd::move(ticket); + + totalTickets++; } - // Check is success spawn - tickets.empty() ? spawnStatusCode |= SpawnStatus::Fail : spawnStatusCode |= SpawnStatus::Success; - // Call CsvSpawner EBus notification - Finished - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); + // If no tickets were created at all (no entities spawned), send finish immediately + if (totalTickets == 0) + { + spawnStatusCode |= SpawnStatus::Fail; + // Call CsvSpawner EBus notification - Finished + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); + } return tickets; } From b30dda32603d113ba1d41501e2dab47555e94495 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 12:58:27 +0200 Subject: [PATCH 43/47] clang format Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 082a035d..d44a223d 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -338,7 +338,8 @@ namespace CsvSpawner::CsvSpawnerUtils if (completedTickets == totalTickets) { // Call CsvSpawner EBus notification - Finished - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); + CsvSpawnerNotificationBus::Broadcast( + &CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); } }; optionalArgs.m_priority = AzFramework::SpawnablePriority_Lowest; From 2e4d01a0e262dd9ba09f8f1686a55c89b8e13fd7 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 15:31:49 +0200 Subject: [PATCH 44/47] remove unused directives Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 2 +- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 45b116a1..64c40ceb 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -322,7 +322,7 @@ namespace CsvSpawner::CsvSpawnerUtils transformInterface->SetWorldTM(transform); }; optionalArgs.m_completionCallback = - [parentId, &spawnStatusCode, &broadcastSpawnInfo, &tickets, totalTickets, &completedTickets]( + [parentId, &spawnStatusCode, &broadcastSpawnInfo, totalTickets, &completedTickets]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) { if (view.empty()) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h index 71839168..a72ad800 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include From 33459186d415f91a510c4336ace1b0c6e6db3cad Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 15:36:54 +0200 Subject: [PATCH 45/47] clang format Signed-off-by: Wojciech Czerski --- .../Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h | 1 - Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 4 +--- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h index 19af9b94..10aa9727 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerEditorComponent.h @@ -10,7 +10,6 @@ #pragma once - #include #include diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 64c40ceb..710dfa89 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -11,7 +11,6 @@ #include "CsvSpawnerUtils.h" - #include #include @@ -19,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -418,7 +416,7 @@ namespace CsvSpawner::CsvSpawnerUtils ->Property("m_spawnerParentEntityId", BehaviorValueProperty(&SpawnInfo::m_spawnerParentEntityId)); } } - + bool IsTerrainAvailable() { return AzFramework::Terrain::TerrainDataRequestBus::HasHandlers(); diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h index a72ad800..3b828fc8 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.h @@ -131,5 +131,5 @@ namespace CsvSpawner::CsvSpawnerUtils AZ::EntityId m_spawnerParentEntityId; ///< Parent entity ID managing the spawn process. }; - [[nodiscard]] bool IsTerrainAvailable(); //!< @returns True if level has any valid Terrain handlers, false otherwise. + [[nodiscard]] bool IsTerrainAvailable(); //!< @returns True if level has any valid Terrain handlers, false otherwise. } // namespace CsvSpawner::CsvSpawnerUtils From 48cd8d2343a4d1d83bfd07ca59a2acfa65230f12 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Wed, 2 Jul 2025 16:47:19 +0200 Subject: [PATCH 46/47] remove dangling references and pointers | using shared ptr for async lamdas Signed-off-by: Wojciech Czerski --- .../Include/CsvSpawner/CsvSpawnerInterface.h | 8 +-- .../Source/CsvSpawner/CsvSpawnerUtils.cpp | 60 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h index 8c84faea..cc88a54d 100644 --- a/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h +++ b/Gems/CsvSpawner/Code/Include/CsvSpawner/CsvSpawnerInterface.h @@ -34,14 +34,14 @@ namespace CsvSpawner * @brief Called when entity spawning begins. * @param m_spawnInfo Struct holding information about entities to be spawned. */ - virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) = 0; + virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo m_spawnInfo) = 0; /** * @brief Called when entity spawning finishes. * @param m_spawnInfo Struct holding information about entities to be spawned. * @param m_statusCode Status code indicating success, failure and warnings of the spawn. */ - virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; + virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; /// EBus Configuration - Allows multiple listeners to handle events. static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; @@ -62,12 +62,12 @@ namespace CsvSpawner OnEntitiesSpawnBegin, OnEntitiesSpawnFinished); - void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo& m_spawnInfo) override + void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo m_spawnInfo) override { Call(FN_OnEntitiesSpawnBegin, m_spawnInfo); } - void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) override + void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) override { Call(FN_OnEntitiesSpawnFinished, m_spawnInfo, m_statusCode); } diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 710dfa89..2ca9f824 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -11,6 +11,8 @@ #include "CsvSpawnerUtils.h" +#include "AzCore/std/smart_ptr/make_shared.h" + #include #include @@ -223,11 +225,22 @@ namespace CsvSpawner::CsvSpawnerUtils { SpawnInfo broadcastSpawnInfo = SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. - SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. + // SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - + // OnEntitiesSpawnFinished. + auto spawnStatusCode = AZStd::make_shared( + SpawnStatus::Success); // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. // Call CsvSpawner EBus notification - Begin CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnBegin, broadcastSpawnInfo); + // Check if there are no entities to spawn + if (entitiesToSpawn.empty()) + { + *spawnStatusCode |= SpawnStatus::Fail; + CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, *spawnStatusCode); + return {}; + } + auto sceneInterface = AZ::Interface::Get(); AZ_Assert(sceneInterface, "Unable to get physics scene interface"); const auto sceneHandle = sceneInterface->GetSceneHandle(physicsSceneName); @@ -236,6 +249,8 @@ namespace CsvSpawner::CsvSpawnerUtils auto spawner = AZ::Interface::Get(); AZ_Assert(spawner, "Unable to get spawnable entities definition"); + auto pendingSpawns = AZStd::make_shared(static_cast(entitiesToSpawn.size())); + // get parent transform AZ::Transform parentTransform = AZ::Transform::CreateIdentity(); if (parentId.IsValid()) @@ -251,10 +266,6 @@ namespace CsvSpawner::CsvSpawnerUtils } } - // Track how many tickets are spawned and how many have completed - size_t totalTickets = 0; - std::atomic_size_t completedTickets = 0; - for (const auto& entityConfig : entitiesToSpawn) { if (!spawnableAssetConfiguration.contains(entityConfig.m_name)) @@ -262,7 +273,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Error("CsvSpawner", false, "SpawnableAssetConfiguration %s not found", entityConfig.m_name.c_str()); // Add notify code status - spawnStatusCode |= SpawnStatus::Warning; + *spawnStatusCode |= SpawnStatus::Warning; continue; } @@ -293,7 +304,7 @@ namespace CsvSpawner::CsvSpawnerUtils else { // Add notify code status - spawnStatusCode |= SpawnStatus::Warning; + *spawnStatusCode |= SpawnStatus::Warning; continue; // Skip this entity if we can't find a valid position and // place on terrain is enabled. @@ -309,7 +320,7 @@ namespace CsvSpawner::CsvSpawnerUtils if (view.empty()) { // Add notify code status - spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; + *spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; return; } @@ -320,40 +331,31 @@ namespace CsvSpawner::CsvSpawnerUtils transformInterface->SetWorldTM(transform); }; optionalArgs.m_completionCallback = - [parentId, &spawnStatusCode, &broadcastSpawnInfo, totalTickets, &completedTickets]( + [parentId, spawnStatusCode, pendingSpawns, broadcastSpawnInfo]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) { if (view.empty()) { - // Add notify code status - spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; - - return; + *spawnStatusCode |= SpawnStatus::Warning | SpawnStatus::Stopped; + } + else + { + const AZ::Entity* root = *view.begin(); + AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); } - const AZ::Entity* root = *view.begin(); - AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); - completedTickets++; - if (completedTickets == totalTickets) + // Decrement the pending counter + const int remaining = --(*pendingSpawns); + if (remaining == 0) { - // Call CsvSpawner EBus notification - Finished + // All spawns are finished, now broadcast finished notification CsvSpawnerNotificationBus::Broadcast( - &CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); + &CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, *spawnStatusCode); } }; optionalArgs.m_priority = AzFramework::SpawnablePriority_Lowest; spawner->SpawnAllEntities(ticket, optionalArgs); tickets[entityConfig.m_id] = AZStd::move(ticket); - - totalTickets++; - } - - // If no tickets were created at all (no entities spawned), send finish immediately - if (totalTickets == 0) - { - spawnStatusCode |= SpawnStatus::Fail; - // Call CsvSpawner EBus notification - Finished - CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); } return tickets; From 24c4e8dc6d5cde61b06d365c0ef824e876b7ee76 Mon Sep 17 00:00:00 2001 From: Wojciech Czerski Date: Thu, 3 Jul 2025 09:49:24 +0200 Subject: [PATCH 47/47] add spacing Signed-off-by: Wojciech Czerski --- Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp index 2ca9f824..bbe1c1d6 100644 --- a/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp +++ b/Gems/CsvSpawner/Code/Source/CsvSpawner/CsvSpawnerUtils.cpp @@ -225,6 +225,7 @@ namespace CsvSpawner::CsvSpawnerUtils { SpawnInfo broadcastSpawnInfo = SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. + // SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - // OnEntitiesSpawnFinished. auto spawnStatusCode = AZStd::make_shared( @@ -313,6 +314,7 @@ namespace CsvSpawner::CsvSpawnerUtils AZ_Assert(spawner, "Unable to get spawnable entities definition"); AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; AzFramework::EntitySpawnTicket ticket(spawnable); + // Set the pre-spawn callback to set the name of the root entity to the name // of the spawnable optionalArgs.m_preInsertionCallback = [transform, &spawnStatusCode](auto id, auto view) @@ -330,6 +332,7 @@ namespace CsvSpawner::CsvSpawnerUtils auto* transformInterface = root->FindComponent(); transformInterface->SetWorldTM(transform); }; + optionalArgs.m_completionCallback = [parentId, spawnStatusCode, pendingSpawns, broadcastSpawnInfo]( [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) @@ -353,6 +356,7 @@ namespace CsvSpawner::CsvSpawnerUtils &CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, *spawnStatusCode); } }; + optionalArgs.m_priority = AzFramework::SpawnablePriority_Lowest; spawner->SpawnAllEntities(ticket, optionalArgs); tickets[entityConfig.m_id] = AZStd::move(ticket);