mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			394 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			394 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    This file is part of TON Blockchain Library.
 | 
						|
 | 
						|
    TON Blockchain Library is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU Lesser General Public License as published by
 | 
						|
    the Free Software Foundation, either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    TON Blockchain Library is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public License
 | 
						|
    along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
    Copyright 2017-2020 Telegram Systems LLP
 | 
						|
*/
 | 
						|
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include "td/utils/Slice.h"
 | 
						|
 | 
						|
#include <atomic>
 | 
						|
#include <memory>
 | 
						|
#include <new>
 | 
						|
#include <type_traits>
 | 
						|
 | 
						|
namespace td {
 | 
						|
 | 
						|
namespace detail {
 | 
						|
struct SharedSliceHeader {
 | 
						|
  explicit SharedSliceHeader(size_t size) : size_{size} {
 | 
						|
  }
 | 
						|
 | 
						|
  void inc() {
 | 
						|
    refcnt_.fetch_add(1, std::memory_order_relaxed);
 | 
						|
  }
 | 
						|
 | 
						|
  bool dec() {
 | 
						|
    return refcnt_.fetch_sub(1, std::memory_order_acq_rel) == 1;
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_unique() const {
 | 
						|
    // NB: race if std::memory_order_relaxed is used
 | 
						|
    // reader may see a change by a new writer
 | 
						|
    return refcnt_.load(std::memory_order_acquire) == 1;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    return size_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  std::atomic<uint64> refcnt_{1};
 | 
						|
  size_t size_;
 | 
						|
};
 | 
						|
 | 
						|
struct UniqueSliceHeader {
 | 
						|
  explicit UniqueSliceHeader(size_t size) : size_{size} {
 | 
						|
  }
 | 
						|
 | 
						|
  void inc() {
 | 
						|
  }
 | 
						|
 | 
						|
  bool dec() {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_unique() const {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    return size_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  size_t size_;
 | 
						|
};
 | 
						|
 | 
						|
template <class HeaderT, bool zero_on_destruct = false>
 | 
						|
class UnsafeSharedSlice {
 | 
						|
 public:
 | 
						|
  UnsafeSharedSlice() = default;
 | 
						|
  UnsafeSharedSlice clone() const {
 | 
						|
    if (is_null()) {
 | 
						|
      return UnsafeSharedSlice();
 | 
						|
    }
 | 
						|
    header()->inc();
 | 
						|
    return UnsafeSharedSlice(ptr_.get());
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_null() const {
 | 
						|
    return !ptr_;
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_unique() const {
 | 
						|
    if (is_null()) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    return header()->is_unique();
 | 
						|
  }
 | 
						|
 | 
						|
  MutableSlice as_mutable_slice() {
 | 
						|
    if (is_null()) {
 | 
						|
      return MutableSlice();
 | 
						|
    }
 | 
						|
    return MutableSlice(ptr_.get() + sizeof(HeaderT), header()->size());
 | 
						|
  }
 | 
						|
 | 
						|
  Slice as_slice() const {
 | 
						|
    if (is_null()) {
 | 
						|
      return Slice();
 | 
						|
    }
 | 
						|
    return Slice(ptr_.get() + sizeof(HeaderT), header()->size());
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    if (is_null()) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    return header()->size();
 | 
						|
  }
 | 
						|
 | 
						|
  static UnsafeSharedSlice create(size_t size) {
 | 
						|
    static_assert(std::is_standard_layout<HeaderT>::value, "HeaderT must have statdard layout");
 | 
						|
    auto ptr = std::make_unique<char[]>(sizeof(HeaderT) + size);
 | 
						|
    auto header_ptr = new (ptr.get()) HeaderT(size);
 | 
						|
    CHECK(header_ptr == reinterpret_cast<HeaderT *>(ptr.get()));
 | 
						|
 | 
						|
    return UnsafeSharedSlice(std::move(ptr));
 | 
						|
  }
 | 
						|
 | 
						|
  static UnsafeSharedSlice create(Slice slice) {
 | 
						|
    auto res = create(slice.size());
 | 
						|
    res.as_mutable_slice().copy_from(slice);
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  void clear() {
 | 
						|
    ptr_.reset();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  explicit UnsafeSharedSlice(char *ptr) : ptr_(ptr) {
 | 
						|
  }
 | 
						|
  explicit UnsafeSharedSlice(std::unique_ptr<char[]> from) : ptr_(from.release()) {
 | 
						|
  }
 | 
						|
 | 
						|
  HeaderT *header() const {
 | 
						|
    return reinterpret_cast<HeaderT *>(ptr_.get());
 | 
						|
  }
 | 
						|
 | 
						|
  struct SharedSliceDestructor {
 | 
						|
    void operator()(char *ptr) {
 | 
						|
      auto header = reinterpret_cast<HeaderT *>(ptr);
 | 
						|
      if (header->dec()) {
 | 
						|
        if (zero_on_destruct) {
 | 
						|
          MutableSlice(ptr, sizeof(HeaderT) + header->size()).fill_zero_secure();
 | 
						|
        }
 | 
						|
        std::default_delete<char[]>()(ptr);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  std::unique_ptr<char[], SharedSliceDestructor> ptr_;
 | 
						|
};
 | 
						|
}  // namespace detail
 | 
						|
 | 
						|
class BufferSlice;
 | 
						|
 | 
						|
class UniqueSharedSlice;
 | 
						|
 | 
						|
class SharedSlice {
 | 
						|
  using Impl = detail::UnsafeSharedSlice<detail::SharedSliceHeader>;
 | 
						|
 | 
						|
 public:
 | 
						|
  SharedSlice() = default;
 | 
						|
 | 
						|
  explicit SharedSlice(Slice slice) : impl_(Impl::create(slice)) {
 | 
						|
  }
 | 
						|
 | 
						|
  explicit SharedSlice(UniqueSharedSlice from);
 | 
						|
 | 
						|
  SharedSlice(const char *ptr, size_t size) : SharedSlice(Slice(ptr, size)) {
 | 
						|
  }
 | 
						|
 | 
						|
  SharedSlice clone() const {
 | 
						|
    return SharedSlice(impl_.clone());
 | 
						|
  }
 | 
						|
 | 
						|
  Slice as_slice() const {
 | 
						|
    return impl_.as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  BufferSlice clone_as_buffer_slice() const;
 | 
						|
 | 
						|
  operator Slice() const {
 | 
						|
    return as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  const char *data() const {
 | 
						|
    return as_slice().data();
 | 
						|
  }
 | 
						|
 | 
						|
  char operator[](size_t at) const {
 | 
						|
    return as_slice()[at];
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return size() == 0;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    return impl_.size();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  size_t length() const {
 | 
						|
    return size();
 | 
						|
  }
 | 
						|
 | 
						|
  void clear() {
 | 
						|
    impl_.clear();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  friend class UniqueSharedSlice;
 | 
						|
  explicit SharedSlice(Impl impl) : impl_(std::move(impl)) {
 | 
						|
  }
 | 
						|
  Impl impl_;
 | 
						|
};
 | 
						|
 | 
						|
class UniqueSharedSlice {
 | 
						|
  using Impl = detail::UnsafeSharedSlice<detail::SharedSliceHeader>;
 | 
						|
 | 
						|
 public:
 | 
						|
  UniqueSharedSlice() = default;
 | 
						|
 | 
						|
  explicit UniqueSharedSlice(size_t size) : impl_(Impl::create(size)) {
 | 
						|
  }
 | 
						|
  explicit UniqueSharedSlice(Slice slice) : impl_(Impl::create(slice)) {
 | 
						|
  }
 | 
						|
 | 
						|
  UniqueSharedSlice(const char *ptr, size_t size) : UniqueSharedSlice(Slice(ptr, size)) {
 | 
						|
  }
 | 
						|
  explicit UniqueSharedSlice(SharedSlice from) : impl_() {
 | 
						|
    if (from.impl_.is_unique()) {
 | 
						|
      impl_ = std::move(from.impl_);
 | 
						|
    } else {
 | 
						|
      impl_ = Impl::create(from.as_slice());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  UniqueSharedSlice copy() const {
 | 
						|
    return UniqueSharedSlice(as_slice());
 | 
						|
  }
 | 
						|
 | 
						|
  Slice as_slice() const {
 | 
						|
    return impl_.as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  MutableSlice as_mutable_slice() {
 | 
						|
    return impl_.as_mutable_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  operator Slice() const {
 | 
						|
    return as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  char *data() {
 | 
						|
    return as_mutable_slice().data();
 | 
						|
  }
 | 
						|
  const char *data() const {
 | 
						|
    return as_slice().data();
 | 
						|
  }
 | 
						|
  char operator[](size_t at) const {
 | 
						|
    return as_slice()[at];
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return size() == 0;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    return impl_.size();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  size_t length() const {
 | 
						|
    return size();
 | 
						|
  }
 | 
						|
 | 
						|
  void clear() {
 | 
						|
    impl_.clear();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  friend class SharedSlice;
 | 
						|
  explicit UniqueSharedSlice(Impl impl) : impl_(std::move(impl)) {
 | 
						|
  }
 | 
						|
  Impl impl_;
 | 
						|
};
 | 
						|
 | 
						|
inline SharedSlice::SharedSlice(UniqueSharedSlice from) : impl_(std::move(from.impl_)) {
 | 
						|
}
 | 
						|
 | 
						|
template <bool zero_on_destruct>
 | 
						|
class UniqueSliceImpl {
 | 
						|
  using Impl = detail::UnsafeSharedSlice<detail::UniqueSliceHeader, zero_on_destruct>;
 | 
						|
 | 
						|
 public:
 | 
						|
  UniqueSliceImpl() = default;
 | 
						|
 | 
						|
  explicit UniqueSliceImpl(size_t size) : impl_(Impl::create(size)) {
 | 
						|
  }
 | 
						|
  UniqueSliceImpl(size_t size, char c) : impl_(Impl::create(size)) {
 | 
						|
    as_mutable_slice().fill(c);
 | 
						|
  }
 | 
						|
  explicit UniqueSliceImpl(Slice slice) : impl_(Impl::create(slice)) {
 | 
						|
  }
 | 
						|
 | 
						|
  UniqueSliceImpl(const char *ptr, size_t size) : UniqueSliceImpl(Slice(ptr, size)) {
 | 
						|
  }
 | 
						|
 | 
						|
  UniqueSliceImpl copy() const {
 | 
						|
    return UniqueSliceImpl(as_slice());
 | 
						|
  }
 | 
						|
 | 
						|
  Slice as_slice() const {
 | 
						|
    return impl_.as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  MutableSlice as_mutable_slice() {
 | 
						|
    return impl_.as_mutable_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  operator Slice() const {
 | 
						|
    return as_slice();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  char *data() {
 | 
						|
    return as_mutable_slice().data();
 | 
						|
  }
 | 
						|
  const char *data() const {
 | 
						|
    return as_slice().data();
 | 
						|
  }
 | 
						|
  char operator[](size_t at) const {
 | 
						|
    return as_slice()[at];
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return size() == 0;
 | 
						|
  }
 | 
						|
 | 
						|
  size_t size() const {
 | 
						|
    return impl_.size();
 | 
						|
  }
 | 
						|
 | 
						|
  // like in std::string
 | 
						|
  size_t length() const {
 | 
						|
    return size();
 | 
						|
  }
 | 
						|
 | 
						|
  void clear() {
 | 
						|
    impl_.clear();
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  explicit UniqueSliceImpl(Impl impl) : impl_(std::move(impl)) {
 | 
						|
  }
 | 
						|
  Impl impl_;
 | 
						|
};
 | 
						|
 | 
						|
using UniqueSlice = UniqueSliceImpl<false>;
 | 
						|
using SecureString = UniqueSliceImpl<true>;
 | 
						|
 | 
						|
inline MutableSlice as_mutable_slice(UniqueSharedSlice &unique_shared_slice) {
 | 
						|
  return unique_shared_slice.as_mutable_slice();
 | 
						|
}
 | 
						|
 | 
						|
inline MutableSlice as_mutable_slice(UniqueSlice &unique_slice) {
 | 
						|
  return unique_slice.as_mutable_slice();
 | 
						|
}
 | 
						|
 | 
						|
inline MutableSlice as_mutable_slice(SecureString &secure_string) {
 | 
						|
  return secure_string.as_mutable_slice();
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace td
 |