diff --git a/doc/core.qbk b/doc/core.qbk index 80e5fae..bce8975 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -70,6 +70,7 @@ criteria for inclusion is that the utility component be: [include null_deleter.qbk] [include fclose_deleter.qbk] [include nvp.qbk] +[include pointer_in_range.qbk] [include pointer_traits.qbk] [include quick_exit.qbk] [include ref.qbk] diff --git a/doc/pointer_in_range.qbk b/doc/pointer_in_range.qbk new file mode 100644 index 0000000..8a21df9 --- /dev/null +++ b/doc/pointer_in_range.qbk @@ -0,0 +1,80 @@ +[/ +Copyright 2024 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +] + +[section:pointer_in_range pointer_in_range] + +[simplesect Authors] + +* Glen Fernandes + +[endsimplesect] + +[section Overview] + +The header provides the function template +`boost::pointer_in_range` to check if a pointer is in a given range. This +can be used in constant expressions in C++14 or higher when the compiler has a +builtin to support `std::is_constant_evaluated`. + +[endsect] + +[section Examples] + +The following is an example of an allocator's deallocation function that does +nothing if the pointer falls within a small automatically allocated buffer. + +``` +template +void +Allocator::deallocate(pointer ptr, size_type) +{ + if (!boost::pointer_in_range(ptr, &buffer_[0], &buffer_[N])) { + ::operator delete(ptr); + } +} +``` + +[endsect] + +[section Reference] + +``` +namespace boost { + +template +constexpr bool pointer_in_range(const T* ptr, const T* begin, const T* end); + +} /* boost */ +``` + +[section Functions] + +[variablelist +[[`template constexpr bool pointer_in_range(const T* ptr, +const T* begin, T* end);`] +[[variablelist +[[Returns][`true` if `ptr` is in range `[begin,end)`, otherwise `false`.]]]]]] + +[endsect] + +[endsect] + +[section Notes] + +If `boost::pointer_in_range` is not usable in constant expressions the macro +`BOOST_CORE_NO_CONSTEXPR_POINTER_IN_RANGE` is defined. + +[endsect] + +[section History] + +Glen Fernandes implemented `pointer_in_range`. + +[endsect] + +[endsect] diff --git a/include/boost/core/pointer_in_range.hpp b/include/boost/core/pointer_in_range.hpp new file mode 100644 index 0000000..4957ff8 --- /dev/null +++ b/include/boost/core/pointer_in_range.hpp @@ -0,0 +1,49 @@ +/* +Copyright 2024 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_POINTER_IN_RANGE_HPP +#define BOOST_CORE_POINTER_IN_RANGE_HPP + +#include +#include + +#if !defined(BOOST_NO_CXX14_CONSTEXPR) +#if defined(BOOST_MSVC) && BOOST_MSVC >= 1925 +#define BOOST_CORE_DETAIL_HAS_IS_CONSTEVAL +#elif defined(__has_builtin) +#if __has_builtin(__builtin_is_constant_evaluated) +#define BOOST_CORE_DETAIL_HAS_IS_CONSTEVAL +#endif +#endif +#endif + +#if !defined(BOOST_CORE_DETAIL_HAS_IS_CONSTEVAL) +#define BOOST_CORE_NO_CONSTEXPR_POINTER_IN_RANGE +#endif + +namespace boost { + +template +inline BOOST_CONSTEXPR bool +pointer_in_range(const T* p, const T* b, const T* e) +{ +#if defined(BOOST_CORE_DETAIL_HAS_IS_CONSTEVAL) + if ( __builtin_is_constant_evaluated()) { + for (; b != e; ++b) { + if (b == p) { + return true; + } + } + return false; + } +#endif + return std::less_equal()(b, p) && std::less()(p, e); +} + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0051ec2..e1d1f92 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -416,5 +416,8 @@ run sp_thread_sleep_test.cpp ; run yield_prim_windows_h_test.cpp ; run yield_prim_pthread_cancel_test.cpp : ; +run pointer_in_range_test.cpp ; +compile pointer_in_range_constexpr_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/pointer_in_range_constexpr_test.cpp b/test/pointer_in_range_constexpr_test.cpp new file mode 100644 index 0000000..f695ff9 --- /dev/null +++ b/test/pointer_in_range_constexpr_test.cpp @@ -0,0 +1,31 @@ +/* +Copyright 2024 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +#if !defined(BOOST_CORE_NO_CONSTEXPR_POINTER_IN_RANGE) +int a[4] = { 0, 0, 0, 0 }; +int n = 0; +const int b[4] = { 0, 0, 0, 0 }; +const int m = 0; + +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&a[0], &a[1], a + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&a[1], &a[1], a + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&a[2], &a[1], a + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&a[3], &a[1], a + 4)); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(a + 4, &a[1], a + 4)); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&n, &a[0], &a[3])); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&m, &a[0], &a[3])); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&b[0], &b[1], b + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&b[1], &b[1], b + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&b[2], &b[1], b + 4)); +BOOST_STATIC_ASSERT(boost::pointer_in_range(&b[3], &b[1], b + 4)); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(b + 4, &b[1], b + 4)); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&n, &b[0], &b[3])); +BOOST_STATIC_ASSERT(!boost::pointer_in_range(&m, &b[0], &b[3])); +#endif diff --git a/test/pointer_in_range_test.cpp b/test/pointer_in_range_test.cpp new file mode 100644 index 0000000..d89d545 --- /dev/null +++ b/test/pointer_in_range_test.cpp @@ -0,0 +1,32 @@ +/* +Copyright 2024 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +int main() +{ + int a[4] = { 0, 0, 0, 0 }; + int n = 0; + const int b[4] = { 0, 0, 0, 0 }; + const int m = 0; + BOOST_TEST(!boost::pointer_in_range(&a[0], &a[1], a + 4)); + BOOST_TEST(boost::pointer_in_range(&a[1], &a[1], a + 4)); + BOOST_TEST(boost::pointer_in_range(&a[2], &a[1], a + 4)); + BOOST_TEST(boost::pointer_in_range(&a[3], &a[1], a + 4)); + BOOST_TEST(!boost::pointer_in_range(a + 4, &a[1], a + 4)); + BOOST_TEST(!boost::pointer_in_range(&n, &a[0], &a[3])); + BOOST_TEST(!boost::pointer_in_range(&m, &a[0], &a[3])); + BOOST_TEST(!boost::pointer_in_range(&b[0], &b[1], b + 4)); + BOOST_TEST(boost::pointer_in_range(&b[1], &b[1], b + 4)); + BOOST_TEST(boost::pointer_in_range(&b[2], &b[1], b + 4)); + BOOST_TEST(boost::pointer_in_range(&b[3], &b[1], b + 4)); + BOOST_TEST(!boost::pointer_in_range(b + 4, &b[1], b + 4)); + BOOST_TEST(!boost::pointer_in_range(&n, &b[0], &b[3])); + BOOST_TEST(!boost::pointer_in_range(&m, &b[0], &b[3])); + return boost::report_errors(); +}