From 837d6535432634125932ce55cc3a71701ec1ac44 Mon Sep 17 00:00:00 2001 From: Rasmus Thomsen Date: Fri, 2 Feb 2024 15:32:39 +0100 Subject: [PATCH] boost: add upstream patch to fix build w/ c++20 on macOS --- recipes/boost/all/conandata.yml | 4 + ...reimplement-string_set-as-any-string.patch | 337 ++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 recipes/boost/all/patches/1.84.0-reimplement-string_set-as-any-string.patch diff --git a/recipes/boost/all/conandata.yml b/recipes/boost/all/conandata.yml index da5e5a928df63..f0c416fba2531 100644 --- a/recipes/boost/all/conandata.yml +++ b/recipes/boost/all/conandata.yml @@ -72,6 +72,10 @@ patches: - patch_file: "patches/1.82.0-locale-iconv-library-option.patch" patch_description: "Optional flag to specify iconv from either libc of libiconv" patch_type: "conan" + - patch_file: "patches/1.84.0-reimplement-string_set-as-any-string.patch" + patch_description: "Fix compilation with cppstd=20 on libcxx platforms (e.g. MacOS)" + patch_type: "official" + patch_source: "https://github.com/boostorg/locale/commit/c5e8f02c903696a213fc4b710f6740ccd1f07f4e" "1.83.0": - patch_file: "patches/1.82.0-locale-iconv-library-option.patch" patch_description: "Optional flag to specify iconv from either libc of libiconv" diff --git a/recipes/boost/all/patches/1.84.0-reimplement-string_set-as-any-string.patch b/recipes/boost/all/patches/1.84.0-reimplement-string_set-as-any-string.patch new file mode 100644 index 0000000000000..15393721de8ee --- /dev/null +++ b/recipes/boost/all/patches/1.84.0-reimplement-string_set-as-any-string.patch @@ -0,0 +1,337 @@ +Fixes compilation with cppstd=20 on MacOS + +From c5e8f02c903696a213fc4b710f6740ccd1f07f4e Mon Sep 17 00:00:00 2001 +From: Alexander Grund +Date: Sun, 3 Dec 2023 20:06:27 +0100 +Subject: [PATCH] Reimplement `string_set` as `any_string` + +Use a better name for a type-erased string implemented using +`dynamic_cast` instead of storing&comparing the `typeid` of the char +type used. +This is a workaround for missing typeinfo for `char8_t` on e.g. libc++ +on FreeBSD 13.1. +It also simplifies memory management size calc/copy implementation. +--- + boost/locale/detail/any_string.hpp | 71 ++++++++++++++++++++++ + boost/locale/formatting.hpp | 51 ++-------------- + libs/locale/src/boost/locale/formatting.cpp | 45 -------------- + libs/locale/test/test_ios_info.cpp | 64 +++++++++++++++---- + 4 files changed, 127 insertions(+), 104 deletions(-) + create mode 100644 boost/locale/detail/any_string.hpp + +diff --git a/boost/locale/detail/any_string.hpp b/boost/locale/detail/any_string.hpp +new file mode 100644 +index 00000000..c0cc7ffb +--- /dev/null ++++ b/boost/locale/detail/any_string.hpp +@@ -0,0 +1,71 @@ ++// ++// Copyright (c) 2023 Alexander Grund ++// ++// Distributed under the Boost Software License, Version 1.0. ++// https://www.boost.org/LICENSE_1_0.txt ++ ++#ifndef BOOST_LOCALE_DETAIL_ANY_STRING_HPP_INCLUDED ++#define BOOST_LOCALE_DETAIL_ANY_STRING_HPP_INCLUDED ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/// \cond INTERNAL ++namespace boost { namespace locale { namespace detail { ++ /// Type-erased std::basic_string ++ class any_string { ++ struct BOOST_SYMBOL_VISIBLE base { ++ virtual ~base() = default; ++ virtual base* clone() const = 0; ++ ++ protected: ++ base() = default; ++ base(const base&) = default; ++ base(base&&) = delete; ++ base& operator=(const base&) = default; ++ base& operator=(base&&) = delete; ++ }; ++ template ++ struct BOOST_SYMBOL_VISIBLE impl : base { ++ explicit impl(const boost::basic_string_view value) : s(value) {} ++ impl* clone() const override { return new impl(*this); } ++ std::basic_string s; ++ }; ++ ++ std::unique_ptr s_; ++ ++ public: ++ any_string() = default; ++ any_string(const any_string& other) : s_(other.s_ ? other.s_->clone() : nullptr) {} ++ any_string(any_string&&) = default; ++ any_string& operator=(any_string other) // Covers the copy and move assignment ++ { ++ s_.swap(other.s_); ++ return *this; ++ } ++ ++ template ++ void set(const boost::basic_string_view s) ++ { ++ BOOST_ASSERT(!s.empty()); ++ s_.reset(new impl(s)); ++ } ++ ++ template ++ std::basic_string get() const ++ { ++ if(!s_) ++ throw std::bad_cast(); ++ return dynamic_cast&>(*s_).s; ++ } ++ }; ++ ++}}} // namespace boost::locale::detail ++ ++/// \endcond ++ ++#endif +diff --git a/boost/locale/formatting.hpp b/boost/locale/formatting.hpp +index d14e6f69..e3c8619e 100644 +--- a/boost/locale/formatting.hpp ++++ b/boost/locale/formatting.hpp +@@ -8,15 +8,13 @@ + #ifndef BOOST_LOCALE_FORMATTING_HPP_INCLUDED + #define BOOST_LOCALE_FORMATTING_HPP_INCLUDED + ++#include + #include +-#include +-#include + #include + #include + #include + #include + #include +-#include + + #ifdef BOOST_MSVC + # pragma warning(push) +@@ -130,13 +128,13 @@ namespace boost { namespace locale { + template + void date_time_pattern(const std::basic_string& str) + { +- date_time_pattern_set().set(str); ++ datetime_.set(str); + } + /// Get date/time pattern (strftime like) + template + std::basic_string date_time_pattern() const + { +- return date_time_pattern_set().get(); ++ return datetime_.get(); + } + + /// \cond INTERNAL +@@ -144,51 +142,10 @@ namespace boost { namespace locale { + /// \endcond + + private: +- class string_set; +- +- const string_set& date_time_pattern_set() const; +- string_set& date_time_pattern_set(); +- +- class BOOST_LOCALE_DECL string_set { +- public: +- string_set(); +- ~string_set(); +- string_set(const string_set& other); +- string_set& operator=(string_set other); +- void swap(string_set& other); +- +- template +- void set(const boost::basic_string_view s) +- { +- BOOST_ASSERT(!s.empty()); +- delete[] ptr; +- ptr = nullptr; +- type = &typeid(Char); +- size = sizeof(Char) * s.size(); +- ptr = size ? new char[size] : nullptr; +- memcpy(ptr, s.data(), size); +- } +- +- template +- std::basic_string get() const +- { +- if(type == nullptr || *type != typeid(Char)) +- throw std::bad_cast(); +- std::basic_string result(size / sizeof(Char), Char(0)); +- memcpy(&result.front(), ptr, size); +- return result; +- } +- +- private: +- const std::type_info* type; +- size_t size; +- char* ptr; +- }; +- + uint64_t flags_; + int domain_id_; + std::string time_zone_; +- string_set datetime_; ++ detail::any_string datetime_; + }; + + /// \brief This namespace includes all manipulators that can be used on IO streams +diff --git a/src/boost/locale/shared/formatting.cpp b/src/boost/locale/shared/formatting.cpp +index 489d1fd5..457ba782 100644 +--- a/libs/locale/src/boost/locale/shared/formatting.cpp ++++ b/libs/locale/src/boost/locale/shared/formatting.cpp +@@ -7,43 +7,8 @@ + #include + #include + #include "boost/locale/shared/ios_prop.hpp" +-#include +-#include + + namespace boost { namespace locale { +- +- ios_info::string_set::string_set() : type(nullptr), size(0), ptr(nullptr) {} +- ios_info::string_set::~string_set() +- { +- delete[] ptr; +- } +- ios_info::string_set::string_set(const string_set& other) +- { +- if(other.ptr != nullptr) { +- ptr = new char[other.size]; +- size = other.size; +- type = other.type; +- memcpy(ptr, other.ptr, size); +- } else { +- ptr = nullptr; +- size = 0; +- type = nullptr; +- } +- } +- +- void ios_info::string_set::swap(string_set& other) +- { +- std::swap(type, other.type); +- std::swap(size, other.size); +- std::swap(ptr, other.ptr); +- } +- +- ios_info::string_set& ios_info::string_set::operator=(string_set other) +- { +- swap(other); +- return *this; +- } +- + ios_info::ios_info() : flags_(0), domain_id_(0), time_zone_(time_zone::global()) {} + + ios_info::~ios_info() = default; +@@ -105,16 +70,6 @@ namespace boost { namespace locale { + return time_zone_; + } + +- const ios_info::string_set& ios_info::date_time_pattern_set() const +- { +- return datetime_; +- } +- +- ios_info::string_set& ios_info::date_time_pattern_set() +- { +- return datetime_; +- } +- + ios_info& ios_info::get(std::ios_base& ios) + { + return impl::ios_prop::get(ios); +diff --git a/libs/locale/test/test_ios_info.cpp b/libs/locale/test/test_ios_info.cpp +index 9b63aaed..79179a8f 100644 +--- a/libs/locale/test/test_ios_info.cpp ++++ b/libs/locale/test/test_ios_info.cpp +@@ -105,18 +105,6 @@ void test_member_methods() + + info.date_time_pattern(std::string("Pattern")); + TEST_EQ(info.date_time_pattern(), "Pattern"); +- +- info.date_time_pattern(ascii_to("WChar Pattern")); +- TEST_EQ(info.date_time_pattern(), ascii_to("WChar Pattern")); +- TEST_THROWS(info.date_time_pattern(), std::bad_cast); +- +- info.date_time_pattern(ascii_to("Char16 Pattern")); +- TEST_THROWS(info.date_time_pattern(), std::bad_cast); +- TEST_EQ(info.date_time_pattern(), ascii_to("Char16 Pattern")); +- +- info.date_time_pattern(ascii_to("Char32 Pattern")); +- TEST_THROWS(info.date_time_pattern(), std::bad_cast); +- TEST_EQ(info.date_time_pattern(), ascii_to("Char32 Pattern")); + } + } + +@@ -212,8 +200,60 @@ void test_manipulators() + TEST_EQ(info2.date_time_pattern(), L"My TZ"); + } + ++void test_any_string() ++{ ++ boost::locale::detail::any_string s; ++ TEST_THROWS(s.get(), std::bad_cast); ++ TEST_THROWS(s.get(), std::bad_cast); ++ ++ s.set("Char Pattern"); ++ TEST_EQ(s.get(), "Char Pattern"); ++ TEST_THROWS(s.get(), std::bad_cast); ++ ++ s.set(ascii_to("WChar Pattern")); ++ TEST_EQ(s.get(), ascii_to("WChar Pattern")); ++ TEST_THROWS(s.get(), std::bad_cast); ++ ++ s.set(ascii_to("Char16 Pattern")); ++ TEST_EQ(s.get(), ascii_to("Char16 Pattern")); ++ TEST_THROWS(s.get(), std::bad_cast); ++ ++ s.set(ascii_to("Char32 Pattern")); ++ TEST_EQ(s.get(), ascii_to("Char32 Pattern")); ++ TEST_THROWS(s.get(), std::bad_cast); ++ ++#ifndef BOOST_LOCALE_NO_CXX20_STRING8 ++ s.set(ascii_to("Char8 Pattern")); ++ TEST_EQ(s.get(), ascii_to("Char8 Pattern")); ++ TEST_THROWS(s.get(), std::bad_cast); ++#endif ++ ++ boost::locale::detail::any_string s1, s2, empty; ++ s1.set("Char"); ++ s2.set(ascii_to("WChar")); ++ // Copy ctor ++ boost::locale::detail::any_string s3(s1); ++ TEST_EQ(s3.get(), "Char"); ++ TEST_EQ(s1.get(), "Char"); ++ // Ensure deep copy ++ s3.set("Foo"); ++ TEST_EQ(s3.get(), "Foo"); ++ TEST_EQ(s1.get(), "Char"); ++ // Copy assign ++ s3 = s2; ++ TEST_EQ(s3.get(), ascii_to("WChar")); ++ TEST_EQ(s2.get(), ascii_to("WChar")); ++ // Move assign ++ s3 = std::move(s1); ++ TEST_EQ(s3.get(), "Char"); ++ // From empty ++ s3 = empty; ++ TEST_THROWS(s3.get(), std::bad_cast); ++} ++ + void test_main(int /*argc*/, char** /*argv*/) + { ++ test_any_string(); + test_member_methods(); + test_manipulators(); + }