diff --git a/include/libpmemobj++/experimental/inline_string.hpp b/include/libpmemobj++/experimental/inline_string.hpp index 064325ff03..c78b50ad48 100644 --- a/include/libpmemobj++/experimental/inline_string.hpp +++ b/include/libpmemobj++/experimental/inline_string.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /** * @file @@ -30,6 +30,9 @@ namespace experimental * This class serves similar purpose to pmem::obj::string, but * keeps the data within the same allocation as inline_string itself. * + * Unlike other containers, it can be used on pmem and dram. Modifiers (like + * assign()) can only be called if inline string is kept on pmem). + * * The data is always kept right after the inline_string structure. * It means that creating an object of inline_string must be done * as follows: @@ -97,17 +100,12 @@ using inline_u32string = basic_inline_string; /** * Constructs inline string from a string_view. - * - * @throw pool_error if inline_string doesn't reside on pmem. */ template basic_inline_string::basic_inline_string( basic_string_view v) : size_(v.size()), capacity_(v.size()) { - if (nullptr == pmemobj_pool_by_ptr(this)) - throw pmem::pool_error("Invalid pool handle."); - std::copy(v.data(), v.data() + static_cast(size_), data()); data()[static_cast(size_)] = '\0'; @@ -115,32 +113,22 @@ basic_inline_string::basic_inline_string( /** * Constructs empty inline_string with specified capacity. - * - * @throw pool_error if inline_string doesn't reside on pmem. */ template basic_inline_string::basic_inline_string(size_type capacity) : size_(0), capacity_(capacity) { - if (nullptr == pmemobj_pool_by_ptr(this)) - throw pmem::pool_error("Invalid pool handle."); - data()[static_cast(size_)] = '\0'; } /** * Copy constructor - * - * @throw pool_error if inline_string doesn't reside on pmem. */ template basic_inline_string::basic_inline_string( const basic_inline_string &rhs) : size_(rhs.size()), capacity_(rhs.capacity()) { - if (nullptr == pmemobj_pool_by_ptr(this)) - throw pmem::pool_error("Invalid pool handle."); - std::copy(rhs.data(), rhs.data() + static_cast(size_), data()); @@ -366,12 +354,17 @@ basic_inline_string::snapshotted_data(size_t p, size_t n) * Transactionally assign content of basic_string_view. * * @throw std::out_of_range if rhs is larger than capacity. + * @throw pool_error if inline string is not on pmem. */ template basic_inline_string & basic_inline_string::assign(basic_string_view rhs) { - auto pop = obj::pool_base(pmemobj_pool_by_ptr(this)); + auto cpop = pmemobj_pool_by_ptr(this); + if (nullptr == cpop) + throw pmem::pool_error("Invalid pool handle."); + + auto pop = pool_base(cpop); if (rhs.size() > capacity()) throw std::out_of_range("inline_string capacity exceeded."); diff --git a/tests/inline_string/inline_string.cpp b/tests/inline_string/inline_string.cpp index c4ea079e26..ae94e19160 100644 --- a/tests/inline_string/inline_string.cpp +++ b/tests/inline_string/inline_string.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2016-2020, Intel Corporation */ +/* Copyright 2016-2021, Intel Corporation */ #include "unittest.hpp" @@ -247,59 +247,43 @@ test_inline_string(nvobj::pool> &pop) }); } +/* test if inline_string can be placed on dram */ template void -test_ctor_exception_nopmem(nvobj::pool> &pop) +test_dram(nvobj::pool> &pop) { - auto bs1 = std::basic_string(4, static_cast('a')); - nvobj::basic_string_view bsv_test_string1(bs1.data(), bs1.length()); + using string_type = nvobj::experimental::basic_inline_string; - try { - std::string example_str("example"); - std::basic_string bs(example_str.begin(), example_str.end()); - Object o( - 1, nvobj::basic_string_view(bs.data(), bs.length())); - UT_ASSERT(0); - } catch (pmem::pool_error &) { - } catch (...) { - UT_ASSERT(0); - } + constexpr size_t string_size = 20; + typename std::aligned_storage::type buffer; - auto r = pop.root(); + std::basic_string s(string_size, T('a')); - const auto req_capacity = 100; + auto dram_location = reinterpret_cast(&buffer); + new (dram_location) + string_type(nvobj::basic_string_view(s.data(), s.length())); - nvobj::transaction::run(pop, [&] { - nvobj::standard_alloc_policy allocator; - r->o1 = static_cast>>( - allocator.allocate(sizeof(Object) + - req_capacity * sizeof(T))); + UT_ASSERT(nvobj::basic_string_view(s.data(), s.length()) == + nvobj::basic_string_view(*dram_location)); - new (r->o1.get()) Object(1, bsv_test_string1); + dram_location->~string_type(); - try { - Object o(*r->o1); - UT_ASSERT(0); - } catch (pmem::pool_error &) { - } catch (...) { - UT_ASSERT(0); - } - }); -} + new (dram_location) string_type(string_size); -template -void -test_ctor_exception(void) -{ + UT_ASSERTeq(dram_location->capacity(), string_size); + UT_ASSERTeq(dram_location->size(), 0); + + /* inline_string cannot be modified on dram. */ try { - int capacity = 10; - nvobjex::basic_inline_string( - static_cast( - capacity)); - UT_ASSERT(0); + s = std::basic_string(string_size / 2, T('b')); + dram_location->assign(s.data()); + + ASSERT_UNREACHABLE; } catch (pmem::pool_error &) { } catch (...) { - UT_ASSERT(0); + ASSERT_UNREACHABLE; } } } @@ -324,8 +308,8 @@ test(int argc, char *argv[]) } test_inline_string(pop); - test_ctor_exception_nopmem(pop); - test_ctor_exception(); + test_dram(pop); + pop.close(); }