smallobj.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #pragma once
  2. #include "pool.h"
  3. #include "alloc.h"
  4. #include <util/generic/utility.h>
  5. #include <util/generic/intrlist.h>
  6. class TFixedSizeAllocator {
  7. struct TAlloc: public TIntrusiveSListItem<TAlloc> {
  8. inline void* ToPointer() noexcept {
  9. return this;
  10. }
  11. static inline TAlloc* FromPointer(void* ptr) noexcept {
  12. return (TAlloc*)ptr;
  13. }
  14. static constexpr size_t EntitySize(size_t alloc) noexcept {
  15. return Max(sizeof(TAlloc), alloc);
  16. }
  17. static constexpr size_t EntityAlign(size_t align) noexcept {
  18. return Max(alignof(TAlloc), align);
  19. }
  20. static inline TAlloc* Construct(void* ptr) noexcept {
  21. return (TAlloc*)ptr;
  22. }
  23. };
  24. public:
  25. using IGrowPolicy = TMemoryPool::IGrowPolicy;
  26. TFixedSizeAllocator(size_t allocSize, IAllocator* alloc)
  27. : TFixedSizeAllocator(allocSize, alignof(TAlloc), TMemoryPool::TExpGrow::Instance(), alloc)
  28. {
  29. }
  30. TFixedSizeAllocator(size_t allocSize, size_t alignSize, IAllocator* alloc)
  31. : TFixedSizeAllocator(allocSize, alignSize, TMemoryPool::TExpGrow::Instance(), alloc)
  32. {
  33. }
  34. TFixedSizeAllocator(size_t allocSize, IGrowPolicy* grow, IAllocator* alloc)
  35. : TFixedSizeAllocator(allocSize, alignof(TAlloc), grow, alloc)
  36. {
  37. }
  38. TFixedSizeAllocator(size_t allocSize, size_t alignSize, IGrowPolicy* grow, IAllocator* alloc)
  39. : Pool_(allocSize, grow, alloc)
  40. , AlignSize_(TAlloc::EntityAlign(alignSize))
  41. , AllocSize_(TAlloc::EntitySize(allocSize))
  42. {
  43. }
  44. inline void* Allocate() {
  45. if (Y_UNLIKELY(Free_.Empty())) {
  46. return Pool_.Allocate(AllocSize_, AlignSize_);
  47. }
  48. return Free_.PopFront()->ToPointer();
  49. }
  50. inline void Release(void* ptr) noexcept {
  51. Free_.PushFront(TAlloc::FromPointer(ptr));
  52. }
  53. inline size_t Size() const noexcept {
  54. return AllocSize_;
  55. }
  56. private:
  57. TMemoryPool Pool_;
  58. const size_t AlignSize_;
  59. const size_t AllocSize_;
  60. TIntrusiveSList<TAlloc> Free_;
  61. };
  62. template <class T>
  63. class TSmallObjAllocator {
  64. public:
  65. using IGrowPolicy = TFixedSizeAllocator::IGrowPolicy;
  66. inline TSmallObjAllocator(IAllocator* alloc)
  67. : Alloc_(sizeof(T), alignof(T), alloc)
  68. {
  69. }
  70. inline TSmallObjAllocator(IGrowPolicy* grow, IAllocator* alloc)
  71. : Alloc_(sizeof(T), alignof(T), grow, alloc)
  72. {
  73. }
  74. inline T* Allocate() {
  75. return (T*)Alloc_.Allocate();
  76. }
  77. inline void Release(T* t) noexcept {
  78. Alloc_.Release(t);
  79. }
  80. private:
  81. TFixedSizeAllocator Alloc_;
  82. };
  83. template <class T>
  84. class TObjectFromPool {
  85. public:
  86. struct THeader {
  87. void* Pool;
  88. // Can't just use T because THeader must be standard layout type for offsetof to work.
  89. alignas(T) char Obj[sizeof(T)];
  90. };
  91. using TPool = TSmallObjAllocator<THeader>;
  92. inline void* operator new(size_t, TPool* pool) {
  93. THeader* ret = pool->Allocate();
  94. ret->Pool = pool;
  95. return &ret->Obj;
  96. }
  97. inline void operator delete(void* ptr, size_t) noexcept {
  98. DoDelete(ptr);
  99. }
  100. inline void operator delete(void* ptr, TPool*) noexcept {
  101. /*
  102. * this delete operator can be called automagically by compiler
  103. */
  104. DoDelete(ptr);
  105. }
  106. private:
  107. static inline void DoDelete(void* ptr) noexcept {
  108. static_assert(std::is_standard_layout<THeader>::value, "offsetof is only defined for standard layout types");
  109. THeader* header = (THeader*)((char*)ptr - offsetof(THeader, Obj));
  110. ((TPool*)header->Pool)->Release(header);
  111. }
  112. };