Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions include/boost/capy/embed.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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)
//
// Official repository: https://github.com/cppalliance/capy
//

#ifndef BOOST_CAPY_EMBED_HPP
#define BOOST_CAPY_EMBED_HPP

#include <boost/capy/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>

#if __cpp_lib_string_view >= 201606L
# include <string_view>
#endif

namespace boost {
namespace capy {

/** Embed a string literal as a string_view

The embed class template is used to embed a string literal
in source code as a string_view. The first character of
the string literal will be removed, typically this is a
newline, allowing the string to be formatted nicely in code.

@par Example
@code
embed text(R"(
Hello "world"
This has quotes and )
)");
core::string_view sv = text.get();
@endcode
The resulting string_view `sv` will contain:
```
Hello "world"
This has quotes and )
```
*/
struct embed
{
/** Constructor
The string literal `s` should be a raw string literal.
The first character (typically a newline) will be
removed from the resulting string_view.
@param s The string literal
*/
template<std::size_t N>
constexpr
embed(
const char (&s)[N]) noexcept
: s_(s + 1, N - 2)
{
}

/** Conversion to string_view
*/
operator core::string_view() const noexcept
{
return s_;
}

#if __cpp_lib_string_view >= 201606L
/** Conversion to std::string_view
*/
operator std::string_view() const noexcept
{
return std::string_view(s_.data(), s_.size());
}
#endif

/** Return the string_view
*/
core::string_view
get() const noexcept
{
return s_;
}

/** Dereference operator
*/
core::string_view
operator*() const noexcept
{
return s_;
}

/** Member access operator
*/
core::string_view const*
operator->() const noexcept
{
return &s_;
}

private:
core::string_view s_;
};

} // capy
} // boost

#endif
71 changes: 61 additions & 10 deletions include/boost/capy/neunique_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define BOOST_CAPY_NEUNIQUE_PTR_HPP

#include <boost/capy/detail/config.hpp>
#include <boost/assert.hpp>
#include <cstddef>
#include <functional>
#include <memory>
Expand All @@ -24,6 +25,33 @@ namespace detail {

//----------------------------------------------------------

template<class U>
auto try_delete(U* p, int) noexcept
-> decltype(sizeof(U), void())
{
delete p;
}

template<class U>
void try_delete(U*, long) noexcept
{
// Incomplete type - should never reach here
std::terminate();
}

template<class U>
auto try_delete_array(U* p, int) noexcept
-> decltype(sizeof(U), void())
{
delete[] p;
}

template<class U>
void try_delete_array(U*, long) noexcept
{
std::terminate();
}

/** Storage wrapper applying empty base optimization.

When `T` is empty and non-final, inherits from it to
Expand Down Expand Up @@ -253,6 +281,12 @@ struct control_block_array final
std::size_t size;
// Flexible array member follows

explicit control_block_array(A const& a)
: alloc_storage(alloc_type(a))
, size(0)
{
}

alloc_type& get_alloc() noexcept
{
return alloc_storage::get();
Expand Down Expand Up @@ -489,10 +523,11 @@ class neunique_ptr
: ptr_(p)
, cb_(other.cb_)
{
// aliasing requires control block; use allocate_neunique
BOOST_ASSERT((other.cb_ != nullptr || other.ptr_ == nullptr));
other.ptr_ = nullptr;
other.cb_ = nullptr;
}

/** Move constructor.

Takes ownership from `other`. After construction,
Expand Down Expand Up @@ -550,7 +585,7 @@ class neunique_ptr
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
delete ptr_;
detail::try_delete(ptr_, 0);
}

//------------------------------------------------------
Expand All @@ -577,7 +612,7 @@ class neunique_ptr
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
delete ptr_;
detail::try_delete(ptr_, 0);
ptr_ = other.ptr_;
cb_ = other.cb_;
other.ptr_ = nullptr;
Expand Down Expand Up @@ -648,7 +683,7 @@ class neunique_ptr
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
delete ptr_;
detail::try_delete(ptr_, 0);
ptr_ = p;
cb_ = nullptr;
}
Expand Down Expand Up @@ -903,6 +938,8 @@ class neunique_ptr<T[]>
: ptr_(p)
, cb_(other.cb_)
{
// aliasing requires control block; use allocate_neunique
BOOST_ASSERT((other.cb_ != nullptr || other.ptr_ == nullptr));
other.ptr_ = nullptr;
other.cb_ = nullptr;
}
Expand Down Expand Up @@ -944,7 +981,7 @@ class neunique_ptr<T[]>
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
delete[] ptr_;
detail::try_delete_array(ptr_, 0);
}

//------------------------------------------------------
Expand All @@ -971,7 +1008,7 @@ class neunique_ptr<T[]>
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
delete[] ptr_;
detail::try_delete_array(ptr_, 0);
ptr_ = other.ptr_;
cb_ = other.cb_;
other.ptr_ = nullptr;
Expand Down Expand Up @@ -1000,6 +1037,22 @@ class neunique_ptr<T[]>
//
//------------------------------------------------------

/** Replace the owned array.

Releases the currently owned array.

@post `get() == nullptr`
*/
void reset() noexcept
{
if(cb_)
cb_->destroy_and_deallocate();
else if(ptr_)
detail::try_delete_array(ptr_, 0);
ptr_ = nullptr;
cb_ = nullptr;
}

/** Replace the owned array.

Releases the currently owned array and takes
Expand All @@ -1013,7 +1066,7 @@ class neunique_ptr<T[]>
template<class U, class = typename std::enable_if<
std::is_same<U, T*>::value ||
std::is_same<U, std::nullptr_t>::value>::type>
void reset(U p = nullptr) noexcept
void reset(U p) noexcept
{
if(cb_)
cb_->destroy_and_deallocate();
Expand Down Expand Up @@ -1232,9 +1285,7 @@ allocate_neunique(A const& a, std::size_t n)
auto guard = detail::make_scope_guard(
[&]{ alloc_traits::deallocate(alloc, cb, units); });

::new(static_cast<void*>(cb)) cb_type();
cb->get_alloc() = alloc;
cb->size = 0;
::new(static_cast<void*>(cb)) cb_type(a);

U* arr = cb->get();
for(std::size_t i = 0; i < n; ++i)
Expand Down
63 changes: 63 additions & 0 deletions test/unit/embed.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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)
//
// Official repository: https://github.com/cppalliance/capy
//

// Test that header file is self-contained.
#include <boost/capy/embed.hpp>

#include "test_suite.hpp"

#if __cpp_lib_string_view >= 201606L
# include <string_view>
#endif

namespace boost {
namespace capy {

namespace {

embed text(R"(
Hello "world"
This has quotes and )
)");

} // (anon)

struct embed_test
{
core::string_view good =
"Hello \"world\"\nThis has quotes and )\n";

void check(core::string_view s)
{
BOOST_TEST_EQ(s, good);
}

#if __cpp_lib_string_view >= 201606L
void check_std(std::string_view s)
{
BOOST_TEST_EQ(s, good);
}
#endif

void run()
{
check(text);
#if __cpp_lib_string_view >= 201606L
check_std(text);
#endif
BOOST_TEST_EQ(text.get(), good);
BOOST_TEST_EQ(*text, good);
BOOST_TEST_EQ(text->data(), good);
}
};

TEST_SUITE(embed_test, "boost.capy.embed");

} // capy
} // boost
Loading
Loading