// Copyright 2013 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_DETAIL_HEAP_ONLY_STRING_HPP #define JSONCONS_DETAIL_HEAP_ONLY_STRING_HPP #include #include #include #include #include // std::memcpy #include // std::allocator #include namespace jsoncons { namespace detail { // From boost 1_71 template T launder_cast(U* u) { #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 return std::launder(reinterpret_cast(u)); #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 800 return __builtin_launder(reinterpret_cast(u)); #else return reinterpret_cast(u); #endif } template class heap_only_string_base { Allocator alloc_; public: Allocator& get_allocator() { return alloc_; } const Allocator& get_allocator() const { return alloc_; } protected: heap_only_string_base(const Allocator& alloc) : alloc_(alloc) { } ~heap_only_string_base() noexcept = default; }; template class heap_only_string_factory; template class heap_only_string_wrapper; template class heap_only_string : public heap_only_string_base { typedef typename std::allocator_traits::template rebind_alloc allocator_type; using allocator_traits_type = std::allocator_traits; using pointer = typename allocator_traits_type::pointer; friend class heap_only_string_factory; friend class heap_only_string_wrapper; pointer p_; size_t length_; public: using char_type = CharT; ~heap_only_string() noexcept = default; const char_type* c_str() const { return to_plain_pointer(p_); } const char_type* data() const { return to_plain_pointer(p_); } std::size_t length() const { return length_; } using heap_only_string_base::get_allocator; friend std::basic_ostream& operator<<(std::basic_ostream& os, const heap_only_string& s) { os.write(s.data(),s.length()); return os; } private: heap_only_string() : heap_only_string_base(Allocator()), p_(nullptr), length_(0) { } heap_only_string(const Allocator& alloc) : heap_only_string_base(alloc), p_(nullptr), length_(0) { } heap_only_string(const heap_only_string&) = delete; heap_only_string& operator=(const heap_only_string&) = delete; }; template class heap_only_string_wrapper { using char_type = CharT; typedef typename std::allocator_traits::template rebind_alloc byte_allocator_type; using byte_pointer = typename std::allocator_traits::pointer; typedef typename std::allocator_traits::template rebind_alloc> string_allocator_type; using string_pointer = typename std::allocator_traits::pointer; using string_type = heap_only_string; struct string_storage { string_type data; char_type c[1]; }; typedef typename std::aligned_storage::type storage_kind; string_pointer ptr_; public: heap_only_string_wrapper() = default; heap_only_string_wrapper(string_pointer ptr) : ptr_(ptr) { } heap_only_string_wrapper(const char_type* data, std::size_t length, const Allocator& a) { ptr_ = create(data,length,a); } heap_only_string_wrapper(const heap_only_string_wrapper& val) { ptr_ = create(val.data(),val.length(),val.get_allocator()); } heap_only_string_wrapper(const heap_only_string_wrapper& val, const Allocator& a) { ptr_ = create(val.data(),val.length(),a); } ~heap_only_string_wrapper() noexcept { if (ptr_ != nullptr) { destroy(ptr_); } } void swap(heap_only_string_wrapper& other) noexcept { std::swap(ptr_,other.ptr_); } const char_type* data() const { return ptr_->data(); } const char_type* c_str() const { return ptr_->c_str(); } std::size_t length() const { return ptr_->length(); } Allocator get_allocator() const { return ptr_->get_allocator(); } private: static size_t aligned_size(std::size_t n) { return sizeof(storage_kind) + n; } static string_pointer create(const char_type* s, std::size_t length, const Allocator& alloc) { std::size_t mem_size = aligned_size(length*sizeof(char_type)); byte_allocator_type byte_alloc(alloc); byte_pointer ptr = byte_alloc.allocate(mem_size); //byte_pointer ptr = std::allocator_traits::allocate(alloc, mem_size); char* storage = to_plain_pointer(ptr); string_type* ps = new(storage)heap_only_string(byte_alloc); auto psa = launder_cast(storage); CharT* p = new(&psa->c)char_type[length + 1]; std::memcpy(p, s, length*sizeof(char_type)); p[length] = 0; ps->p_ = std::pointer_traits::pointer_to(*p); ps->length_ = length; return std::pointer_traits::pointer_to(*ps); } static void destroy(string_pointer ptr) { string_type* rawp = to_plain_pointer(ptr); char* p = launder_cast(rawp); std::size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); byte_allocator_type byte_alloc(ptr->get_allocator()); byte_alloc.deallocate(p,mem_size); } }; }} #endif