monotonic_resource.ipp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/json
  9. //
  10. #ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
  11. #define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
  12. #include <boost/json/monotonic_resource.hpp>
  13. #include <boost/json/detail/except.hpp>
  14. #include <boost/core/max_align.hpp>
  15. #include <memory>
  16. namespace boost {
  17. namespace json {
  18. struct alignas(core::max_align_t)
  19. monotonic_resource::block : block_base
  20. {
  21. };
  22. constexpr
  23. std::size_t
  24. monotonic_resource::
  25. max_size()
  26. {
  27. return std::size_t(-1) - sizeof(block);
  28. }
  29. // lowest power of 2 greater than or equal to n
  30. std::size_t
  31. monotonic_resource::
  32. round_pow2(
  33. std::size_t n) noexcept
  34. {
  35. if(n & (n - 1))
  36. return next_pow2(n);
  37. return n;
  38. }
  39. // lowest power of 2 greater than n
  40. std::size_t
  41. monotonic_resource::
  42. next_pow2(
  43. std::size_t n) noexcept
  44. {
  45. std::size_t result = min_size_;
  46. while(result <= n)
  47. {
  48. if(result >= max_size() - result)
  49. {
  50. // overflow
  51. result = max_size();
  52. break;
  53. }
  54. result *= 2;
  55. }
  56. return result;
  57. }
  58. //----------------------------------------------------------
  59. monotonic_resource::
  60. ~monotonic_resource()
  61. {
  62. release();
  63. }
  64. monotonic_resource::
  65. monotonic_resource(
  66. std::size_t initial_size,
  67. storage_ptr upstream) noexcept
  68. : buffer_{
  69. nullptr, 0, 0, nullptr}
  70. , next_size_(round_pow2(initial_size))
  71. , upstream_(std::move(upstream))
  72. {
  73. }
  74. monotonic_resource::
  75. monotonic_resource(
  76. unsigned char* buffer,
  77. std::size_t size,
  78. storage_ptr upstream) noexcept
  79. : buffer_{
  80. buffer, size, size, nullptr}
  81. , next_size_(next_pow2(size))
  82. , upstream_(std::move(upstream))
  83. {
  84. }
  85. void
  86. monotonic_resource::
  87. release() noexcept
  88. {
  89. auto p = head_;
  90. while(p != &buffer_)
  91. {
  92. auto next = p->next;
  93. upstream_->deallocate(p, p->size);
  94. p = next;
  95. }
  96. buffer_.p = reinterpret_cast<
  97. unsigned char*>(buffer_.p) - (
  98. buffer_.size - buffer_.avail);
  99. buffer_.avail = buffer_.size;
  100. head_ = &buffer_;
  101. }
  102. void*
  103. monotonic_resource::
  104. do_allocate(
  105. std::size_t n,
  106. std::size_t align)
  107. {
  108. auto p = std::align(align, n, head_->p, head_->avail);
  109. if(p)
  110. {
  111. head_->p = reinterpret_cast<
  112. unsigned char*>(p) + n;
  113. head_->avail -= n;
  114. return p;
  115. }
  116. if(next_size_ < n)
  117. next_size_ = round_pow2(n);
  118. auto b = ::new(upstream_->allocate(
  119. sizeof(block) + next_size_)) block;
  120. b->p = b + 1;
  121. b->avail = next_size_;
  122. b->size = next_size_;
  123. b->next = head_;
  124. head_ = b;
  125. next_size_ = next_pow2(next_size_);
  126. p = std::align(align, n, head_->p, head_->avail);
  127. BOOST_ASSERT(p);
  128. head_->p = reinterpret_cast<
  129. unsigned char*>(p) + n;
  130. head_->avail -= n;
  131. return p;
  132. }
  133. void
  134. monotonic_resource::
  135. do_deallocate(
  136. void*,
  137. std::size_t,
  138. std::size_t)
  139. {
  140. // do nothing
  141. }
  142. bool
  143. monotonic_resource::
  144. do_is_equal(
  145. memory_resource const& mr) const noexcept
  146. {
  147. return this == &mr;
  148. }
  149. } // namespace json
  150. } // namespace boost
  151. #endif