Hide key template instances behind factory functions.

And provide a separate "module library"
Update testing scripts.
This commit is contained in:
jzmaddock
2024-04-18 16:37:12 +01:00
parent fbfdda66fd
commit 2c0058a902
45 changed files with 489 additions and 362 deletions

View File

@ -166,11 +166,8 @@ jobs:
- name: Generate headers - name: Generate headers
run: ./b2 headers run: ./b2 headers
working-directory: ../boost-root working-directory: ../boost-root
- name: Test Config
run: CXX=clang++-18 ./config/clang.sh ./config/test_has_module_support.cpp ./config/has_module_support.cpp has_module_support
working-directory: ../boost-root/libs/regex/test/module
- name: Test - name: Test
run: CXX=clang++-18 LIBRARIES="-licuuc -licudata -licui18n" ./test.sh ./config/clang.sh run: CXX=clang++-18 LIBRARIES="-licuuc -licudata -licui18n" ./test_clang.sh
working-directory: ../boost-root/libs/regex/test/module working-directory: ../boost-root/libs/regex/test/module
macos: macos:
runs-on: macos-latest runs-on: macos-latest

View File

@ -650,22 +650,38 @@ private:
// and are designed to provide the strong exception guarantee // and are designed to provide the strong exception guarantee
// (in the event of a throw, the state of the object remains unchanged). // (in the event of a throw, the state of the object remains unchanged).
// //
namespace detail
{
template <class charT, class F, class Traits>
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits> > create_implemenation(const charT* p1, const charT* p2, F f, std::shared_ptr<boost::regex_traits_wrapper<Traits> > ptraits)
{
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits> > result;
if (!ptraits.get())
{
result = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits>());
}
else
{
result = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, Traits>(ptraits));
}
result->assign(p1, p2, f);
return result;
}
#ifdef BOOST_REGEX_AS_MODULE
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<char, basic_regex<char>::traits_type> >
create_implemenation(const char* p1, const char* p2, basic_regex<char>::flag_type f, std::shared_ptr<boost::regex_traits_wrapper<basic_regex<char>::traits_type> > ptraits);
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<wchar_t, basic_regex<wchar_t>::traits_type> >
create_implemenation(const wchar_t* p1, const wchar_t* p2, basic_regex<wchar_t>::flag_type f, std::shared_ptr<boost::regex_traits_wrapper<basic_regex<wchar_t>::traits_type> > ptraits);
#endif
}
template <class charT, class traits> template <class charT, class traits>
basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign(const charT* p1, basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign(const charT* p1,
const charT* p2, const charT* p2,
flag_type f) flag_type f)
{ {
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> > temp; m_pimpl = detail::create_implemenation(p1, p2, f, m_pimpl.get() ? m_pimpl->m_ptraits : std::shared_ptr<boost::regex_traits_wrapper<traits> >());
if(!m_pimpl.get())
{
temp = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits>());
}
else
{
temp = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits>(m_pimpl->m_ptraits));
}
temp->assign(p1, p2, f);
temp.swap(m_pimpl);
return *this; return *this;
} }

View File

@ -558,6 +558,33 @@ private:
#endif #endif
}; };
template <class Matcher>
inline bool factory_match(Matcher& m)
{
return m.match();
}
template <class Matcher>
inline bool factory_find(Matcher& m)
{
return m.find();
}
#ifdef BOOST_REGEX_AS_MODULE
bool factory_match(perl_matcher<const char*, match_results<const char*>::allocator_type, regex::traits_type>& m);
bool factory_match(perl_matcher<const wchar_t*, match_results<const wchar_t*>::allocator_type, wregex::traits_type>& m);
bool factory_match(perl_matcher<std::string::const_iterator, match_results<std::string::const_iterator>::allocator_type, regex::traits_type>& m);
bool factory_match(perl_matcher<std::wstring::const_iterator, match_results<std::wstring::const_iterator>::allocator_type, wregex::traits_type>& m);
bool factory_match(perl_matcher<std::string::iterator, match_results<std::string::iterator>::allocator_type, regex::traits_type>& m);
bool factory_match(perl_matcher<std::wstring::iterator, match_results<std::wstring::iterator>::allocator_type, wregex::traits_type>& m);
bool factory_find(perl_matcher<const char*, match_results<const char*>::allocator_type, regex::traits_type>& m);
bool factory_find(perl_matcher<const wchar_t*, match_results<const wchar_t*>::allocator_type, wregex::traits_type>& m);
bool factory_find(perl_matcher<std::string::const_iterator, match_results<std::string::const_iterator>::allocator_type, regex::traits_type>& m);
bool factory_find(perl_matcher<std::wstring::const_iterator, match_results<std::wstring::const_iterator>::allocator_type, wregex::traits_type>& m);
bool factory_find(perl_matcher<std::string::iterator, match_results<std::string::iterator>::allocator_type, regex::traits_type>& m);
bool factory_find(perl_matcher<std::wstring::iterator, match_results<std::wstring::iterator>::allocator_type, wregex::traits_type>& m);
#endif
} // namespace BOOST_REGEX_DETAIL_NS } // namespace BOOST_REGEX_DETAIL_NS
#ifdef BOOST_REGEX_MSVC #ifdef BOOST_REGEX_MSVC

View File

@ -41,7 +41,7 @@ inline unsigned int regex_grep(Predicate foo,
match_results<BidiIterator> m; match_results<BidiIterator> m;
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_allocator_type, traits> matcher(first, last, m, e, flags, first); BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_allocator_type, traits> matcher(first, last, m, e, flags, first);
unsigned int count = 0; unsigned int count = 0;
while(matcher.find()) while(BOOST_REGEX_DETAIL_NS::factory_find(matcher))
{ {
++count; ++count;
if(0 == foo(m)) if(0 == foo(m))
@ -56,7 +56,7 @@ inline unsigned int regex_grep(Predicate foo,
// a non-NULL one at the same position: // a non-NULL one at the same position:
match_results<BidiIterator, match_allocator_type> m2(m); match_results<BidiIterator, match_allocator_type> m2(m);
matcher.setf(match_not_null | match_continuous); matcher.setf(match_not_null | match_continuous);
if(matcher.find()) if(BOOST_REGEX_DETAIL_NS::factory_find(matcher))
{ {
++count; ++count;
if(0 == foo(m)) if(0 == foo(m))

View File

@ -36,7 +36,7 @@ bool regex_match(BidiIterator first, BidiIterator last,
match_flag_type flags = match_default) match_flag_type flags = match_default)
{ {
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, first); BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, first);
return matcher.match(); return BOOST_REGEX_DETAIL_NS::factory_match(matcher);
} }
BOOST_REGEX_MODULE_EXPORT template <class iterator, class charT, class traits> BOOST_REGEX_MODULE_EXPORT template <class iterator, class charT, class traits>
bool regex_match(iterator first, iterator last, bool regex_match(iterator first, iterator last,

View File

@ -42,7 +42,7 @@ bool regex_search(BidiIterator first, BidiIterator last,
return false; return false;
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, base); BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, base);
return matcher.find(); return BOOST_REGEX_DETAIL_NS::factory_find(matcher);
} }
// //
@ -77,7 +77,7 @@ bool regex_search(BidiIterator first, BidiIterator last,
match_results<BidiIterator> m; match_results<BidiIterator> m;
typedef typename match_results<BidiIterator>::allocator_type match_alloc_type; typedef typename match_results<BidiIterator>::allocator_type match_alloc_type;
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_alloc_type, traits> matcher(first, last, m, e, flags | regex_constants::match_any, first); BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_alloc_type, traits> matcher(first, last, m, e, flags | regex_constants::match_any, first);
return matcher.find(); return BOOST_REGEX_DETAIL_NS::factory_find(matcher);
} }
BOOST_REGEX_MODULE_EXPORT template <class charT, class traits> BOOST_REGEX_MODULE_EXPORT template <class charT, class traits>

View File

@ -5,6 +5,23 @@ module;
#define BOOST_REGEX_USE_STD_MODULE #define BOOST_REGEX_USE_STD_MODULE
#endif #endif
#if __has_include(<unicode/utypes.h>)
#if !defined(BOOST_REGEX_WITH_ICU)
#if defined(_MSC_FULL_VER)
#pragma message "ICU headers are available but building the Regex module with ICU support is turned OFF. Build with BOOST_REGEX_WITH_ICU=1 to turn it on, or BOOST_REGEX_WITH_ICU=0 to disable this message"
#else
# warning "ICU headers are available but building the Regex module with ICU support is turned OFF. Build with BOOST_REGEX_WITH_ICU=1 to turn it on, or BOOST_REGEX_WITH_ICU=0 to disable this message"
#endif
#elif BOOST_REGEX_WITH_ICU
# define BOOST_REGEX_HAS_ICU_HEADERS
#endif
#endif
#if defined(_WIN32) && __has_include(<windows.h>) #if defined(_WIN32) && __has_include(<windows.h>)
#include <windows.h> #include <windows.h>
#endif #endif
@ -52,7 +69,7 @@ module;
#include <cwchar> #include <cwchar>
#endif #endif
#if __has_include(<unicode/utypes.h>) #ifdef BOOST_REGEX_HAS_ICU_HEADERS
#include <unicode/utypes.h> #include <unicode/utypes.h>
#include <unicode/uchar.h> #include <unicode/uchar.h>
#include <unicode/coll.h> #include <unicode/coll.h>
@ -74,8 +91,12 @@ import std.core;
#pragma warning(disable:5244) #pragma warning(disable:5244)
#endif #endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Winclude-angled-in-module-purview"
#endif
#include <boost/regex.hpp> #include <boost/regex.hpp>
#if __has_include(<unicode/utypes.h>) #ifdef BOOST_REGEX_HAS_ICU_HEADERS
#include <boost/regex/icu.hpp> #include <boost/regex/icu.hpp>
#endif #endif

11
module/regex_cfind.cpp Normal file
View File

@ -0,0 +1,11 @@
module boost.regex;
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<const char*, match_results<const char*>::allocator_type, regex::traits_type>& m)
{
return m.find();
}
}

11
module/regex_cmatch.cpp Normal file
View File

@ -0,0 +1,11 @@
module boost.regex;
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<const char*, match_results<const char*>::allocator_type, regex::traits_type>& m)
{
return m.match();
}
}

View File

@ -0,0 +1,31 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <memory>
#endif
#ifndef BOOST_REGEX_DETAIL_NS
#define BOOST_REGEX_DETAIL_NS re_detail_600
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::detail {
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<char, basic_regex<char>::traits_type> >
create_implemenation(const char* p1, const char* p2, basic_regex<char>::flag_type f, std::shared_ptr<boost::regex_traits_wrapper<basic_regex<char>::traits_type> > ptraits)
{
return create_implemenation<char, basic_regex<char>::flag_type, basic_regex<char>::traits_type>(p1, p2, f, ptraits);
}
}

View File

@ -0,0 +1,31 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <memory>
#endif
#ifndef BOOST_REGEX_DETAIL_NS
#define BOOST_REGEX_DETAIL_NS re_detail_600
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::detail {
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<wchar_t, basic_regex<wchar_t>::traits_type> >
create_implemenation(const wchar_t* p1, const wchar_t* p2, basic_regex<wchar_t>::flag_type f, std::shared_ptr<boost::regex_traits_wrapper<basic_regex<wchar_t>::traits_type> > ptraits)
{
return create_implemenation<wchar_t, basic_regex<wchar_t>::flag_type, basic_regex<wchar_t>::traits_type>(p1, p2, f, ptraits);
}
}

26
module/regex_nc_sfind.cpp Normal file
View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<std::string::iterator, match_results<std::string::iterator>::allocator_type, regex::traits_type>& m)
{
return m.find();
}
}

View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<std::string::iterator, match_results<std::string::iterator>::allocator_type, regex::traits_type>& m)
{
return m.match();
}
}

View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<std::wstring::iterator, match_results<std::wstring::iterator>::allocator_type, wregex::traits_type>& m)
{
return m.find();
}
}

View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<std::wstring::iterator, match_results<std::wstring::iterator>::allocator_type, wregex::traits_type>& m)
{
return m.match();
}
}

26
module/regex_sfind.cpp Normal file
View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<std::string::const_iterator, match_results<std::string::const_iterator>::allocator_type, regex::traits_type>& m)
{
return m.find();
}
}

26
module/regex_smatch.cpp Normal file
View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<std::string::const_iterator, match_results<std::string::const_iterator>::allocator_type, regex::traits_type>& m)
{
return m.match();
}
}

11
module/regex_wcfind.cpp Normal file
View File

@ -0,0 +1,11 @@
module boost.regex;
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<const wchar_t*, match_results<const wchar_t*>::allocator_type, wregex::traits_type>& m)
{
return m.find();
}
}

11
module/regex_wcmatch.cpp Normal file
View File

@ -0,0 +1,11 @@
module boost.regex;
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<const wchar_t*, match_results<const wchar_t*>::allocator_type, wregex::traits_type>& m)
{
return m.match();
}
}

26
module/regex_wsfind.cpp Normal file
View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_find(perl_matcher<std::wstring::const_iterator, match_results<std::wstring::const_iterator>::allocator_type, wregex::traits_type>& m)
{
return m.find();
}
}

26
module/regex_wsmatch.cpp Normal file
View File

@ -0,0 +1,26 @@
#if defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))
#define BOOST_REGEX_USE_STD_MODULE
#endif
#ifndef BOOST_REGEX_USE_STD_MODULE
module;
#include <string>
#endif
module boost.regex;
#ifdef BOOST_REGEX_USE_STD_MODULE
import std;
#endif
namespace boost::re_detail_600 {
bool factory_match(perl_matcher<std::wstring::const_iterator, match_results<std::wstring::const_iterator>::allocator_type, wregex::traits_type>& m)
{
return m.match();
}
}

View File

@ -1,17 +0,0 @@
# copyright John Maddock 2022
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt.
project
: requirements
<threading>multi
<toolset>msvc:<asynch-exceptions>on
<toolset>msvc:<cxxstd>latest
<toolset>gcc:<cxxflags>-fmodules-ts
;
obj has_module_support : has_module_support.cpp : <toolset>msvc:<cxxflags>-interface ;
exe test_has_module_support : test_has_module_support.cpp has_module_support : <dependency>has_module_support ;
explicit test_has_module_support ;

View File

@ -1,36 +0,0 @@
#!/bin/sh
#
# Arguments are:
#
# 1) A space spearated list of source files.
# 2) A space separated list of module source files.
# 3) The name of the executable to build.
#
# Environment variables used are:
#
# CXX - the name of the clang compiler, defaults to clang++.
# CXXFLAGS - flags to pass to the build, defaults to "-std=c++20 -g".
# LINKFLAGS - flags to pass to the link stage, defaults to "".
# LIBRARIES - Additional libraries to add to the end of the link command line, defaults to "".
#
: ${CXX:="clang++"}
: ${CXXFLAGS:="-std=c++20 -g"}
module_usage=""
for module_file in $2; do
module_base="${module_file%.*}"
$CXX $CXXFLAGS -x c++-module $module_file --precompile -o $module_base.pcm || exit 1
# grab the name of the exported module from the source:
cxx_module_name=$(grep -E "export[ ]+module[ ]+([^; ]+)" $module_file | sed -r "s/export[ ]+module[ ]+([^; ]+)[ ]*;/\1/")
# Build the command line for module usage:
module_usage="$module_usage -fmodule-file=$cxx_module_name=$module_base.pcm $module_base.pcm"
done
# Build the actual executable:
$CXX $CXXFLAGS $1 $module_usage $LIBRARIES -o $3 || exit 1

View File

@ -1,26 +0,0 @@
/*
*
* Copyright (c) 2022
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
module;
#include <memory>
export module test_support;
export template <class T> struct pimpl
{
private:
std::shared_ptr<T> data;
public:
pimpl(const T& x) : data(new T(x)) {}
pimpl() = default;
};

View File

@ -1,17 +0,0 @@
/*
*
* Copyright (c) 2022
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
import test_support;
int main()
{
pimpl<int> p1, p2(3);
}

View File

@ -16,9 +16,9 @@
* DESCRIPTION: Credit card number formatting code. * DESCRIPTION: Credit card number formatting code.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -1,188 +0,0 @@
/*
*
* Copyright (c) 2004
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE mfc_example.cpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: examples of using Boost.Regex with MFC and ATL string types.
*/
#include <boost/regex/config.hpp>
#ifdef BOOST_HAS_ICU
#include <boost/regex/icu.hpp>
#include <iostream>
#include <assert.h>
//
// Find out if *password* meets our password requirements,
// as defined by the regular expression *requirements*.
//
bool is_valid_password(const U_NAMESPACE_QUALIFIER UnicodeString& password, const U_NAMESPACE_QUALIFIER UnicodeString& requirements)
{
return boost::u32regex_match(password, boost::make_u32regex(requirements));
}
//
// Extract filename part of a path from a UTF-8 encoded std::string and return the result
// as another std::string:
//
std::string get_filename(const std::string& path)
{
boost::u32regex r = boost::make_u32regex("(?:\\A|.*\\\\)([^\\\\]+)");
boost::smatch what;
if(boost::u32regex_match(path, what, r))
{
// extract $1 as a std::string:
return what.str(1);
}
else
{
throw std::runtime_error("Invalid pathname");
}
}
U_NAMESPACE_QUALIFIER UnicodeString extract_greek(const U_NAMESPACE_QUALIFIER UnicodeString& text)
{
// searches through some UTF-16 encoded text for a block encoded in Greek,
// this expression is imperfect, but the best we can do for now - searching
// for specific scripts is actually pretty hard to do right.
boost::u32regex r = boost::make_u32regex(L"[\\x{370}-\\x{3FF}](?:[^[:L*:]]|[\\x{370}-\\x{3FF}])*");
boost::u16match what;
if(boost::u32regex_search(text, what, r))
{
// extract $0 as a UnicodeString:
return U_NAMESPACE_QUALIFIER UnicodeString(what[0].first, what.length(0));
}
else
{
throw std::runtime_error("No Greek found!");
}
}
void enumerate_currencies(const std::string& text)
{
// enumerate and print all the currency symbols, along
// with any associated numeric values:
const char* re =
"([[:Sc:]][[:Cf:][:Cc:][:Z*:]]*)?"
"([[:Nd:]]+(?:[[:Po:]][[:Nd:]]+)?)?"
"(?(1)"
"|(?(2)"
"[[:Cf:][:Cc:][:Z*:]]*"
")"
"[[:Sc:]]"
")";
boost::u32regex r = boost::make_u32regex(re);
boost::u32regex_iterator<std::string::const_iterator> i(boost::make_u32regex_iterator(text, r)), j;
while(i != j)
{
std::cout << (*i)[0] << std::endl;
++i;
}
}
void enumerate_currencies2(const std::string& text)
{
// enumerate and print all the currency symbols, along
// with any associated numeric values:
const char* re =
"([[:Sc:]][[:Cf:][:Cc:][:Z*:]]*)?"
"([[:Nd:]]+(?:[[:Po:]][[:Nd:]]+)?)?"
"(?(1)"
"|(?(2)"
"[[:Cf:][:Cc:][:Z*:]]*"
")"
"[[:Sc:]]"
")";
boost::u32regex r = boost::make_u32regex(re);
boost::u32regex_token_iterator<std::string::const_iterator>
i(boost::make_u32regex_token_iterator(text, r, 1)), j;
while(i != j)
{
std::cout << *i << std::endl;
++i;
}
}
//
// Take a credit card number as a string of digits,
// and reformat it as a human readable string with "-"
// separating each group of four digit;,
// note that we're mixing a UTF-32 regex, with a UTF-16
// string and a UTF-8 format specifier, and it still all
// just works:
//
const boost::u32regex e = boost::make_u32regex("\\A(\\d{3,4})[- ]?(\\d{4})[- ]?(\\d{4})[- ]?(\\d{4})\\z");
const char* human_format = "$1-$2-$3-$4";
U_NAMESPACE_QUALIFIER UnicodeString human_readable_card_number(const U_NAMESPACE_QUALIFIER UnicodeString& s)
{
return boost::u32regex_replace(s, e, human_format);
}
int main()
{
// password checks using u32regex_match:
U_NAMESPACE_QUALIFIER UnicodeString pwd = "abcDEF---";
U_NAMESPACE_QUALIFIER UnicodeString pwd_check = "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}";
bool b = is_valid_password(pwd, pwd_check);
assert(b);
pwd = "abcD-";
b = is_valid_password(pwd, pwd_check);
assert(!b);
// filename extraction with u32regex_match:
std::string file = "abc.hpp";
file = get_filename(file);
assert(file == "abc.hpp");
file = "c:\\a\\b\\c\\d.h";
file = get_filename(file);
assert(file == "d.h");
// Greek text extraction with u32regex_search:
const UChar t[] = {
'S', 'o', 'm', 'e', ' ', 'w', 'h', 'e', 'r', 'e', ' ', 'i', 'n', 0x0391, 0x039D, 0x0395, 0x0398, 0x0391, 0
};
const UChar g[] = {
0x0391, 0x039D, 0x0395, 0x0398, 0x0391, 0
};
U_NAMESPACE_QUALIFIER UnicodeString text = t;
U_NAMESPACE_QUALIFIER UnicodeString greek = extract_greek(text);
assert(greek == g);
// extract currency symbols with associated value, use iterator interface:
std::string text2 = " $100.23 or \xC2\xA3""198.12 "; // \xC2\xA3 is the pound sign encoded in UTF-8
enumerate_currencies(text2);
enumerate_currencies2(text2);
U_NAMESPACE_QUALIFIER UnicodeString credit_card_number = "1234567887654321";
credit_card_number = human_readable_card_number(credit_card_number);
assert(credit_card_number == "1234-5678-8765-4321");
return 0;
}
#else
#include <iostream>
int main()
{
std::cout << "<NOTE>ICU support not enabled, feature unavailable</NOTE>";
return 0;
}
#endif

View File

@ -1,8 +1,26 @@
REM Basic command line to build everything with msvc: REM Basic command line to build everything with msvc:
cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx" del *.obj
cl /std:c++latest /EHsc /nologo /W4 /c /interface /I ..\..\..\.. ..\..\module\regex.cxx del *.exe
del *.lib
cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx" || exit 1
cl /std:c++latest /EHsc /nologo /W4 /c /interface /I ..\..\..\.. ..\..\module\regex.cxx || exit 1
cl /std:c++latest /EHsc /nologo /W4 /c /I ..\..\..\.. ..\..\module\*.cpp || exit 1
lib *.obj /OUT:regex.lib || exit 1
time < nul
for %%f in (*.cpp) do ( for %%f in (*.cpp) do (
cl /std:c++latest /EHsc /nologo /W4 /I ..\..\..\.. %%f std.obj regex.obj cl /std:c++latest /EHsc /nologo /W4 /I ..\..\..\.. %%f regex.lib || exit 1
) )
time < nul
for %%f in (*.cpp) do (
cl /DTEST_HEADERS /std:c++latest /EHsc /nologo /W4 /I ..\..\..\.. %%f || exit 1
)
time < nul

View File

@ -16,9 +16,9 @@
* DESCRIPTION: Search example using partial matches. * DESCRIPTION: Search example using partial matches.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <iostream> #include <iostream>

View File

@ -16,9 +16,9 @@
* DESCRIPTION: Search example using partial matches. * DESCRIPTION: Search example using partial matches.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <iostream> #include <iostream>

View File

@ -19,9 +19,9 @@
//#include <version> //#include <version>
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -16,9 +16,9 @@
* DESCRIPTION: regex_grep example 1: searches a cpp file for class definitions. * DESCRIPTION: regex_grep example 1: searches a cpp file for class definitions.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -17,9 +17,9 @@
* using a global callback function. * using a global callback function.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -17,9 +17,9 @@
* using a bound member function callback. * using a bound member function callback.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -17,9 +17,9 @@
* using global data. * using global data.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -16,9 +16,9 @@
* DESCRIPTION: ftp based regex_match example. * DESCRIPTION: ftp based regex_match example.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <cstdlib> #include <cstdlib>
@ -33,7 +33,6 @@ import std.core;
import boost.regex; import boost.regex;
#endif #endif
using namespace std;
using namespace boost; using namespace boost;
regex expression("^([0-9]+)(\\-| |$)(.*)$"); regex expression("^([0-9]+)(\\-| |$)(.*)$");
@ -52,7 +51,7 @@ int process_ftp(const char* response, std::string* msg)
// what[3] contains the text message. // what[3] contains the text message.
if(msg) if(msg)
msg->assign(what[3].first, what[3].second); msg->assign(what[3].first, what[3].second);
return ::atoi(what[1].first); return std::atoi(what[1].first);
} }
// failure did not match // failure did not match
if(msg) if(msg)
@ -62,6 +61,7 @@ int process_ftp(const char* response, std::string* msg)
int main(int argc, const char*[]) int main(int argc, const char*[])
{ {
using namespace std;
std::string in, out; std::string in, out;
do do
{ {

View File

@ -17,9 +17,9 @@
* converts a C++ file to syntax highlighted HTML. * converts a C++ file to syntax highlighted HTML.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <iostream> #include <iostream>

View File

@ -17,9 +17,9 @@
* converts a C++ file to syntax highlighted HTML. * converts a C++ file to syntax highlighted HTML.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <iostream> #include <iostream>

View File

@ -16,9 +16,9 @@
* DESCRIPTION: regex_search example: searches a cpp file for class definitions. * DESCRIPTION: regex_search example: searches a cpp file for class definitions.
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <string> #include <string>

View File

@ -17,10 +17,10 @@
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; Simport std.core;
#else #else
#include <list> #include <list>
#include <string> #include <string>

View File

@ -17,9 +17,9 @@
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <list> #include <list>

View File

@ -17,9 +17,9 @@
*/ */
#ifdef __cpp_lib_modules #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <iostream> #include <iostream>

View File

@ -16,21 +16,22 @@
* DESCRIPTION: regex_token_iterator example: spit out linked URL's. * DESCRIPTION: regex_token_iterator example: spit out linked URL's.
*/ */
#ifdef TEST_HEADERS #if (defined(__cpp_lib_modules) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 193933523))) && !defined(TEST_HEADERS)
#include <boost/regex.hpp>
#else
import boost.regex;
#endif
#ifdef __cpp_lib_modules
import std; import std;
#elif defined(MSVC_EXPERIMENTAL_STD_MODULE) #elif defined(MSVC_EXPERIMENTAL_STD_MODULE) && !defined(TEST_HEADERS)
import std.core; import std.core;
#else #else
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#endif #endif
#ifdef TEST_HEADERS
#include <boost/regex.hpp>
#else
import boost.regex;
#endif
boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"",
boost::regex::normal | boost::regex::icase); boost::regex::normal | boost::regex::icase);

View File

@ -1,11 +0,0 @@
#!/bin/sh
#
# Builds all of the tests in this folder using the supplied compiler-specific script in $1
#
for file in *.cpp; do
CXXFLAGS="-std=c++20 -g -I ../../../.." $1 $file ../../module/regex.cxx "${file%.*}.exe" || exit 1
done

28
test/module/test_clang.sh Normal file
View File

@ -0,0 +1,28 @@
#!/bin/sh
#
# Builds all of the tests in this folder using clang modules
#
: ${CXX:="clang++"}
: ${CXXFLAGS:="-std=c++20 -g -I../../../.."}
rm *.o *.pcm *.exe
cmd="$CXX $CXXFLAGS -x c++-module ../../module/regex.cxx --precompile -o boost.regex.pcm"
echo $cmd
$cmd || exit 1
cmd="$CXX $CXXFLAGS boost.regex.pcm -c -o regex.o"
echo $cmd
$cmd || exit 1
cmd="$CXX $CXXFLAGS -fprebuilt-module-path=. -c ../../module/*.cpp"
echo $cmd
$cmd || exit 1
for file in *.cpp; do
cmd="$CXX $CXXFLAGS -fprebuilt-module-path=. $file *.o -o ${file%.*}.exe"
echo $cmd
$cmd || exit 1
done