Merge branch 'main' of github.com:Rconybea/refcnt

This commit is contained in:
Roland Conybeare 2024-04-30 10:21:25 -05:00
commit 0680b7b1fc
3 changed files with 274 additions and 270 deletions

View file

@ -8,85 +8,85 @@
#include <utility> // std::index_sequence #include <utility> // std::index_sequence
namespace xo { namespace xo {
namespace reflect { namespace reflect {
template <std::size_t...Idxs> template <std::size_t...Idxs>
constexpr auto constexpr auto
substring_as_array(std::string_view str, substring_as_array(std::string_view str,
std::index_sequence<Idxs...> indexes) std::index_sequence<Idxs...> indexes)
{ {
//return std::array<char, indexes.size()+1>{str[Idxs]..., '\n'}; //return std::array<char, indexes.size()+1>{str[Idxs]..., '\n'};
return std::array<char, indexes.size()>{str[Idxs]...}; return std::array<char, indexes.size()>{str[Idxs]...};
} /*substring_as_array*/ } /*substring_as_array*/
template <typename T> constexpr auto type_name_array() { template <typename T> constexpr auto type_name_array() {
#if defined(__clang__) #if defined(__clang__)
constexpr auto prefix = std::string_view{"[T = "}; constexpr auto prefix = std::string_view{"[T = "};
constexpr auto suffix = std::string_view{"]"}; constexpr auto suffix = std::string_view{"]"};
constexpr auto function = std::string_view{__PRETTY_FUNCTION__}; constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(__GNUC__) #elif defined(__GNUC__)
constexpr auto prefix = std::string_view{"with T = "}; constexpr auto prefix = std::string_view{"with T = "};
constexpr auto suffix = std::string_view{"]"}; constexpr auto suffix = std::string_view{"]"};
constexpr auto function = std::string_view{__PRETTY_FUNCTION__}; constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
constexpr auto prefix = std::string_view{"type_name_array<"}; constexpr auto prefix = std::string_view{"type_name_array<"};
constexpr auto suffix = std::string_view{">(void)"}; constexpr auto suffix = std::string_view{">(void)"};
constexpr auto function = std::string_view{__FUNCSIG__}; constexpr auto function = std::string_view{__FUNCSIG__};
#else #else
# error type_name_array: Unsupported compiler # error type_name_array: Unsupported compiler
#endif #endif
constexpr auto start = function.find(prefix) + prefix.size(); constexpr auto start = function.find(prefix) + prefix.size();
constexpr auto end = function.rfind(suffix); constexpr auto end = function.rfind(suffix);
//static_assert(start < end); //static_assert(start < end);
constexpr auto name = function.substr(start, (end - start)); constexpr auto name = function.substr(start, (end - start));
constexpr auto ixseq = std::make_index_sequence<name.size()>{}; constexpr auto ixseq = std::make_index_sequence<name.size()>{};
return substring_as_array(name, ixseq); return substring_as_array(name, ixseq);
} /*type_name_array*/ } /*type_name_array*/
template <typename T> template <typename T>
struct type_name_holder { struct type_name_holder {
static inline constexpr auto value = type_name_array<T>(); static inline constexpr auto value = type_name_array<T>();
}; };
template <typename T> template <typename T>
constexpr auto type_name() -> std::string_view constexpr auto type_name() -> std::string_view
{ {
constexpr auto& value = type_name_holder<T>::value; constexpr auto& value = type_name_holder<T>::value;
return std::string_view{value.data(), value.size()}; return std::string_view{value.data(), value.size()};
} }
#ifdef NOT_IN_USE #ifdef NOT_IN_USE
template <std::string_view const&... Strs> template <std::string_view const&... Strs>
struct join struct join
{ {
// Join all strings into a single std::array of chars // Join all strings into a single std::array of chars
static constexpr auto impl() noexcept static constexpr auto impl() noexcept
{ {
constexpr std::size_t len = (Strs.size() + ... + 0); constexpr std::size_t len = (Strs.size() + ... + 0);
std::array<char, len + 1> arr{}; std::array<char, len + 1> arr{};
auto append = [i = 0, &arr](auto const& s) mutable { auto append = [i = 0, &arr](auto const& s) mutable {
for (auto c : s) arr[i++] = c; for (auto c : s) arr[i++] = c;
};
(append(Strs), ...);
arr[len] = 0;
return arr;
}
// Give the joined string static storage
static constexpr auto arr = impl();
// View as a std::string_view
static constexpr std::string_view value {arr.data(), arr.size() - 1};
}; };
(append(Strs), ...);
arr[len] = 0;
return arr;
}
// Give the joined string static storage
static constexpr auto arr = impl();
// View as a std::string_view
static constexpr std::string_view value {arr.data(), arr.size() - 1};
};
// Helper to get the value out // Helper to get the value out
template <std::string_view const&... Strs> template <std::string_view const&... Strs>
static constexpr auto join_v = join<Strs...>::value; static constexpr auto join_v = join<Strs...>::value;
#endif #endif
} /*namespace reflect*/ } /*namespace reflect*/
} /*namespace xo*/ } /*namespace xo*/
/* end demangle.hpp */ /* end demangle.hpp */

View file

@ -2,4 +2,8 @@ set(SELF_LIB refcnt)
set(SELF_SRCS Refcounted.cpp Displayable.cpp) set(SELF_SRCS Refcounted.cpp Displayable.cpp)
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
# NOTE:
# dependency set here must be kept consistent with refcnt/cmake/refcntConfig.cmake.in
#
xo_dependency(${SELF_LIB} indentlog) xo_dependency(${SELF_LIB} indentlog)

View file

@ -7,295 +7,295 @@
#include <type_traits> #include <type_traits>
namespace xo { namespace xo {
using xo::ref::Refcount; using xo::ref::Refcount;
using xo::ref::Borrow; using xo::ref::Borrow;
using xo::ref::rp; using xo::ref::rp;
using xo::ref::brw; using xo::ref::brw;
using xo::ref::intrusive_ptr_refcount; using xo::ref::intrusive_ptr_refcount;
using xo::ref::intrusive_ptr_add_ref; using xo::ref::intrusive_ptr_add_ref;
using xo::ref::intrusive_ptr_release; using xo::ref::intrusive_ptr_release;
namespace ut { namespace ut {
namespace { namespace {
static uint32_t ctor_count = 0; static uint32_t ctor_count = 0;
static uint32_t dtor_count = 0; static uint32_t dtor_count = 0;
/* empty object, except for refcount */ /* empty object, except for refcount */
class JustRefcount : public ref::Refcount { class JustRefcount : public ref::Refcount {
public: public:
JustRefcount() { ++ctor_count; } JustRefcount() { ++ctor_count; }
~JustRefcount() { ++dtor_count; } ~JustRefcount() { ++dtor_count; }
}; /*JustRefcount*/ }; /*JustRefcount*/
inline std::ostream & operator<<(std::ostream & os, JustRefcount & x) { inline std::ostream & operator<<(std::ostream & os, JustRefcount & x) {
os << "JustRefcount"; os << "JustRefcount";
return os; return os;
} /*operator<<*/ } /*operator<<*/
} /*namespace*/ } /*namespace*/
TEST_CASE("refcount", "[refcnt][trivial]") { TEST_CASE("refcount", "[refcnt][trivial]") {
REQUIRE(std::is_default_constructible<ref::Refcount>() == true); REQUIRE(std::is_default_constructible<ref::Refcount>() == true);
REQUIRE(std::has_virtual_destructor<ref::Refcount>() == true); REQUIRE(std::has_virtual_destructor<ref::Refcount>() == true);
/* refcount object self-initializes to 0 */ /* refcount object self-initializes to 0 */
Refcount x; Refcount x;
REQUIRE(x.reference_counter() == 0); REQUIRE(x.reference_counter() == 0);
} /*TEST_CASE(refcount)*/ } /*TEST_CASE(refcount)*/
TEST_CASE("null-intrusive-ptr", "[refcnt][trivial]") { TEST_CASE("null-intrusive-ptr", "[refcnt][trivial]") {
//constexpr std::string_view c_self = "TEST_CASE:null-intrusive-ptr"; //constexpr std::string_view c_self = "TEST_CASE:null-intrusive-ptr";
REQUIRE(std::has_virtual_destructor<JustRefcount>() == true); REQUIRE(std::has_virtual_destructor<JustRefcount>() == true);
rp<JustRefcount> p1; rp<JustRefcount> p1;
rp<JustRefcount> p2; rp<JustRefcount> p2;
REQUIRE(sizeof(p1) == sizeof(JustRefcount*)); REQUIRE(sizeof(p1) == sizeof(JustRefcount*));
REQUIRE(p1.get() == nullptr); REQUIRE(p1.get() == nullptr);
REQUIRE(p1.operator->() == nullptr); REQUIRE(p1.operator->() == nullptr);
REQUIRE(p2.get() == nullptr); REQUIRE(p2.get() == nullptr);
REQUIRE(p2.operator->() == nullptr); REQUIRE(p2.operator->() == nullptr);
/* can assign a nullptr */ /* can assign a nullptr */
rp<JustRefcount> p3; rp<JustRefcount> p3;
REQUIRE(p3.get() == nullptr); REQUIRE(p3.get() == nullptr);
p3 = p1; p3 = p1;
REQUIRE(p3.get() == nullptr); REQUIRE(p3.get() == nullptr);
/* can use aux functions on null pointers */ /* can use aux functions on null pointers */
REQUIRE(intrusive_ptr_refcount(p1.get()) == 0); REQUIRE(intrusive_ptr_refcount(p1.get()) == 0);
intrusive_ptr_add_ref(nullptr); intrusive_ptr_add_ref(nullptr);
intrusive_ptr_release(nullptr); intrusive_ptr_release(nullptr);
/* can borrow a null intrusive_ptr */ /* can borrow a null intrusive_ptr */
brw<JustRefcount> p1_brw = p1.borrow(); brw<JustRefcount> p1_brw = p1.borrow();
brw<JustRefcount> p2_brw = p2.borrow(); brw<JustRefcount> p2_brw = p2.borrow();
REQUIRE(p1_brw.get() == nullptr); REQUIRE(p1_brw.get() == nullptr);
REQUIRE(p1_brw.operator->() == nullptr); REQUIRE(p1_brw.operator->() == nullptr);
/* null borrow is false-y */ /* null borrow is false-y */
REQUIRE(p1_brw == false); REQUIRE(p1_brw == false);
/* can promote a borrowed pointer */ /* can promote a borrowed pointer */
rp<JustRefcount> pp = p1_brw.promote(); rp<JustRefcount> pp = p1_brw.promote();
REQUIRE(p1.get() == pp.get()); REQUIRE(p1.get() == pp.get());
/* comparisons */ /* comparisons */
REQUIRE(Borrow<JustRefcount>::compare(p1_brw, p2_brw) == 0); REQUIRE(Borrow<JustRefcount>::compare(p1_brw, p2_brw) == 0);
REQUIRE(p1_brw == p2_brw); REQUIRE(p1_brw == p2_brw);
REQUIRE((p1_brw != p2_brw) == false); REQUIRE((p1_brw != p2_brw) == false);
REQUIRE(p1 == p1_brw); REQUIRE(p1 == p1_brw);
REQUIRE((p1 != p1_brw) == false); REQUIRE((p1 != p1_brw) == false);
REQUIRE(p1_brw == p1); REQUIRE(p1_brw == p1);
REQUIRE((p1_brw != p1) == false); REQUIRE((p1_brw != p1) == false);
} /*TEST_CASE(null-intrusive_ptr)*/ } /*TEST_CASE(null-intrusive_ptr)*/
TEST_CASE("intrusive-ptr-identity", "[refcnt][identity]") TEST_CASE("intrusive-ptr-identity", "[refcnt][identity]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1.get() == p1.operator->()); REQUIRE(p1.get() == p1.operator->());
REQUIRE(intrusive_ptr_refcount(p1.get()) == 1); REQUIRE(intrusive_ptr_refcount(p1.get()) == 1);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
intrusive_ptr_add_ref(p1.get()); intrusive_ptr_add_ref(p1.get());
REQUIRE(intrusive_ptr_refcount(p1.get()) == 2); REQUIRE(intrusive_ptr_refcount(p1.get()) == 2);
intrusive_ptr_release(p1.get()); intrusive_ptr_release(p1.get());
REQUIRE(intrusive_ptr_refcount(p1.get()) == 1); REQUIRE(intrusive_ptr_refcount(p1.get()) == 1);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
rp<JustRefcount> p2(new JustRefcount()); rp<JustRefcount> p2(new JustRefcount());
REQUIRE(ctor_count == cc + 2); REQUIRE(ctor_count == cc + 2);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p2.get() != nullptr); REQUIRE(p2.get() != nullptr);
REQUIRE(p2.get() != p1.get()); REQUIRE(p2.get() != p1.get());
REQUIRE(p2.get() == p2.operator->()); REQUIRE(p2.get() == p2.operator->());
REQUIRE(p2->reference_counter() == 1); REQUIRE(p2->reference_counter() == 1);
/* can borrow a non-null intrusive-ptr */ /* can borrow a non-null intrusive-ptr */
brw<JustRefcount> p1_brw = p1.borrow(); brw<JustRefcount> p1_brw = p1.borrow();
REQUIRE(p1_brw.get() == p1.get()); REQUIRE(p1_brw.get() == p1.get());
/* borrowing does not change refcount, borrow not tracked */ /* borrowing does not change refcount, borrow not tracked */
REQUIRE(ctor_count == cc + 2); REQUIRE(ctor_count == cc + 2);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get()->reference_counter() == 1); REQUIRE(p1.get()->reference_counter() == 1);
/* copying borrowed pointer does not touch refcount */ /* copying borrowed pointer does not touch refcount */
brw<JustRefcount> p1_brw2 = p1_brw; brw<JustRefcount> p1_brw2 = p1_brw;
REQUIRE(ctor_count == cc + 2); REQUIRE(ctor_count == cc + 2);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1_brw2.get() == p1.get()); REQUIRE(p1_brw2.get() == p1.get());
REQUIRE(p1.get()->reference_counter() == 1); REQUIRE(p1.get()->reference_counter() == 1);
} /*TEST_CASE(identity-intrusive-ptr)*/ } /*TEST_CASE(identity-intrusive-ptr)*/
TEST_CASE("intrusive-ptr-release", "[refcnt][release]") TEST_CASE("intrusive-ptr-release", "[refcnt][release]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
/* reference count going to 0 -> delete object */ /* reference count going to 0 -> delete object */
p1 = nullptr; p1 = nullptr;
REQUIRE(p1.get() == nullptr); REQUIRE(p1.get() == nullptr);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc + 1); REQUIRE(dtor_count == dc + 1);
} /*TEST_CASE(intrusive-ptr-release)*/ } /*TEST_CASE(intrusive-ptr-release)*/
TEST_CASE("intrusive-ptr-copy", "[refcnt][copy]") TEST_CASE("intrusive-ptr-copy", "[refcnt][copy]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
JustRefcount * p1_native = p1.get(); JustRefcount * p1_native = p1.get();
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
/* copy ctor ran to make copy of p1, did not allocate */ /* copy ctor ran to make copy of p1, did not allocate */
rp<JustRefcount> p2(p1); rp<JustRefcount> p2(p1);
REQUIRE(p1->reference_counter() == 2); REQUIRE(p1->reference_counter() == 2);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
} /*TEST_CASE(intrusive-ptr-copy)*/ } /*TEST_CASE(intrusive-ptr-copy)*/
TEST_CASE("intrusive-ptr-move", "[refcnt][move]") TEST_CASE("intrusive-ptr-move", "[refcnt][move]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
JustRefcount * p1_native = p1.get(); JustRefcount * p1_native = p1.get();
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
rp<JustRefcount> p2{std::move(p1)}; rp<JustRefcount> p2{std::move(p1)};
REQUIRE(p2->reference_counter() == 1); REQUIRE(p2->reference_counter() == 1);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p2 = nullptr; p2 = nullptr;
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc + 1); REQUIRE(dtor_count == dc + 1);
} /*TEST_CASE(intrusive-ptr-move)*/ } /*TEST_CASE(intrusive-ptr-move)*/
TEST_CASE("instrusive-ptr-assign", "[refcnt][assign]") TEST_CASE("instrusive-ptr-assign", "[refcnt][assign]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
JustRefcount * p1_native = p1.get(); JustRefcount * p1_native = p1.get();
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
rp<JustRefcount> p2; rp<JustRefcount> p2;
REQUIRE(p2.get() == nullptr); REQUIRE(p2.get() == nullptr);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p2 = p1; p2 = p1;
REQUIRE(p2.get() == p1.get()); REQUIRE(p2.get() == p1.get());
REQUIRE(p2->reference_counter() == 2); REQUIRE(p2->reference_counter() == 2);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p1 = nullptr; p1 = nullptr;
REQUIRE(p2->reference_counter() == 1); REQUIRE(p2->reference_counter() == 1);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p2 = nullptr; p2 = nullptr;
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc + 1); REQUIRE(dtor_count == dc + 1);
} /*TEST_CASE(intrusive-ptr-assign)*/ } /*TEST_CASE(intrusive-ptr-assign)*/
TEST_CASE("intrusive-ptr-move-assign", "[refcnt][move-assign]") TEST_CASE("intrusive-ptr-move-assign", "[refcnt][move-assign]")
{ {
uint32_t cc = ctor_count; uint32_t cc = ctor_count;
uint32_t dc = dtor_count; uint32_t dc = dtor_count;
rp<JustRefcount> p1(new JustRefcount()); rp<JustRefcount> p1(new JustRefcount());
JustRefcount * p1_native = p1.get(); JustRefcount * p1_native = p1.get();
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
REQUIRE(p1.get() != nullptr); REQUIRE(p1.get() != nullptr);
REQUIRE(p1->reference_counter() == 1); REQUIRE(p1->reference_counter() == 1);
rp<JustRefcount> p2; rp<JustRefcount> p2;
REQUIRE(p2.get() == nullptr); REQUIRE(p2.get() == nullptr);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p2 = std::move(p1); p2 = std::move(p1);
REQUIRE(p1.get() == nullptr); REQUIRE(p1.get() == nullptr);
REQUIRE(p2.get() == p1_native); REQUIRE(p2.get() == p1_native);
REQUIRE(p2->reference_counter() == 1); REQUIRE(p2->reference_counter() == 1);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p1 = nullptr; /*no-op*/ p1 = nullptr; /*no-op*/
REQUIRE(p2->reference_counter() == 1); REQUIRE(p2->reference_counter() == 1);
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc); REQUIRE(dtor_count == dc);
p2 = nullptr; p2 = nullptr;
REQUIRE(ctor_count == cc + 1); REQUIRE(ctor_count == cc + 1);
REQUIRE(dtor_count == dc + 1); REQUIRE(dtor_count == dc + 1);
} /*TEST_CASE(intrusive-ptr-move-assign)*/ } /*TEST_CASE(intrusive-ptr-move-assign)*/
} /*namespace ut*/ } /*namespace ut*/
} /*namespace xo*/ } /*namespace xo*/
/* end intrusive_ptr.test.cpp */ /* end intrusive_ptr.test.cpp */