• MultilingualSimpleObject


      1 //
      2 // Created by whg on 2020/8/25.
      3 //
      4 #pragma once
      5 #include <utility>
      6 #include <memory>
      7 #include <vector>
      8 #include <chrono>
      9 
     10 namespace typany {
     11 namespace ObjectPool {
     12 
     13     inline int64_t GetCurrentTimeStamp() {
     14         std::chrono::time_point<std::chrono::system_clock> current = std::chrono::system_clock::now();
     15         auto stamp = std::chrono::duration_cast<std::chrono::milliseconds>(current.time_since_epoch());
     16         return stamp.count();
     17     }
     18 
     19     template <typename T, size_t ChunkMaxBlockSize = 128, std::int64_t MaxAccessIntervalMillisecond = 3*60*1000>
     20     class Allocator
     21     {
     22     public:
     23         typedef T               value_type;
     24         typedef T*              pointer;
     25         typedef const T*        const_pointer;
     26 
     27     private:
     28         Allocator() {}
     29         ~Allocator(){
     30             Chunk* chunkPointer = chunk_;
     31             while (chunkPointer != nullptr) {
     32                 Chunk* next = chunkPointer->Next();
     33                 ::delete chunkPointer;
     34                 chunkPointer = next;
     35             }
     36         }
     37 
     38     public:
     39         static Allocator<value_type>& Instance() {
     40             static Allocator<value_type> allocator_;
     41             return allocator_;
     42         }
     43         void* Allocate(size_t size) {
     44             if (size > MaxSize()) {
     45                 throw std::runtime_error("");
     46             }
     47 
     48             if (chunk_ == nullptr) {
     49                 chunk_ = ::new Chunk(ChunkMaxBlockSize, minBlockSize_, align_);
     50             }
     51 
     52             Chunk* chunkPointer = chunk_;
     53             while (chunkPointer != nullptr) {
     54                 if (!chunkPointer->Full() || chunkPointer->Next() == nullptr) {
     55                     break;
     56                 }
     57                 chunkPointer = chunkPointer->Next();
     58             }
     59             if (!chunkPointer->Full()) {
     60                 return chunkPointer->Acquire();
     61             }
     62             if (chunkPointer->Next() == nullptr) {
     63                 chunkPointer->Next(::new Chunk(ChunkMaxBlockSize, minBlockSize_, align_));
     64             }
     65             return chunkPointer->Next()->Acquire();
     66         }
     67 
     68         void Deallocate(void* ptr, size_t length) noexcept {
     69             if (chunk_ == nullptr) {
     70                 throw std::runtime_error("Allocator<T>::allocate(size_t n) 'n' exceeds maximum supported size");
     71             }
     72 
     73             Chunk* chunkPointer = chunk_;
     74             while (chunkPointer != nullptr) {
     75                 if (chunkPointer->InRange(ptr) || chunkPointer->Next() == nullptr) {
     76                     break;
     77                 }
     78                 chunkPointer = chunkPointer->Next();
     79             }
     80             if (chunkPointer->InRange(ptr) && chunkPointer->CheckAddressValid(ptr)) {
     81                 chunkPointer->Release(ptr);
     82             } else {
     83                 throw std::runtime_error("Allocator<T>::allocate(size_t n) 'n' exceeds maximum supported size");
     84             }
     85 
     86             ++deallocateCount_;
     87             ShrinkChunk();
     88         }
     89         inline size_t MaxSize() const noexcept {
     90             return size_t(~0) / type_size_;
     91         }
     92 
     93     private:
     94         // 收缩,超出MaxAccessIntervalMillisecond未访问,且Empty = true,则删掉该Chunk
     95         void ShrinkChunk() {
     96             if (chunk_ == nullptr || deallocateCount_ % ChunkMaxBlockSize != 0) {
     97                 return;
     98             }
     99             // 至少保留一个chunk
    100             Chunk* chunkPointer = chunk_;
    101             while (chunkPointer != nullptr) {
    102                 Chunk* next = chunkPointer->Next();
    103                 if (next == nullptr) {
    104                     break;
    105                 }
    106                 if (next->Idle()) {
    107                     std::int64_t chunkStamp = next->LastReleaseTimeStamp();
    108                     std::int64_t currentStamp = GetCurrentTimeStamp();
    109                     if (currentStamp - chunkStamp >= MaxAccessIntervalMillisecond) {
    110                         chunkPointer->Next(next->Next());
    111                         ::delete next;
    112                     } else {
    113                         chunkPointer = chunkPointer->Next();
    114                     }
    115                 } else {
    116                     chunkPointer = chunkPointer->Next();
    117                 }
    118             }
    119         }
    120     private:
    121         // 数据块,
    122         class Chunk {
    123         public:
    124             Chunk(size_t maxBlockCount, size_t blockSize, size_t align) : maxBlockCount_(maxBlockCount), blockSize_(blockSize), length_(maxBlockCount_*blockSize_), align_(align) {
    125                 unsigned char* address = (unsigned char*)malloc(length_);
    126                 data_ = reinterpret_cast<pointer>(address);
    127                 enabled_ = (data_ != nullptr);
    128                 if (enabled_) {
    129                     idle_.reserve(maxBlockCount_);
    130                     for (size_t i = 0; i < maxBlockCount; ++i) {
    131                         idle_.push_back(i);
    132                     }
    133                 }
    134             }
    135             ~Chunk(){
    136                 Destory();
    137             }
    138             void* Acquire() {
    139                 if (!enabled_ || Full()) {
    140                     return nullptr;
    141                 }
    142                 size_t index = idle_.back();
    143                 idle_.pop_back();
    144                 lastReleaseTimeStamp_ = std::numeric_limits<std::int64_t>::max();
    145                 return IndexToAddress(index);
    146             }
    147             void Release(void* ptr) {
    148                 if (!InRange(ptr) || !CheckAddressValid(ptr)) {
    149                     return;
    150                 }
    151                 size_t index = AddressToIndex(ptr);
    152                 idle_.push_back(index);
    153                 if (Idle()) {
    154                     // 只记最后一次归还的时间
    155                     lastReleaseTimeStamp_ = GetCurrentTimeStamp();
    156                 }
    157             }
    158             void Destory() {
    159                 if (!enabled_) {
    160                     return;
    161                 }
    162                 free(data_);
    163                 idle_.clear();
    164             }
    165             bool Full() const {
    166                 return data_ == nullptr ? true : idle_.empty();
    167             }
    168             bool Idle() const {
    169                 return idle_.size() == ChunkMaxBlockSize;
    170             }
    171             const_pointer Begin() const {
    172                 return data_;
    173             }
    174             pointer End() const {
    175                 return data_ + maxBlockCount_;
    176             }
    177             bool InRange(void* ptr) {
    178                 return (data_ <= reinterpret_cast<pointer>(ptr) && reinterpret_cast<pointer>(ptr) < data_ + maxBlockCount_);
    179             }
    180             bool CheckAddressValid(void* ptr) {
    181                 return (reinterpret_cast<size_t >(ptr) % align_ == 0)
    182                        && ((reinterpret_cast<size_t >(ptr) - reinterpret_cast<size_t >(data_)) % blockSize_ == 0);
    183             }
    184             Chunk* Next() {
    185                 return next_;
    186             }
    187             void Next(Chunk* chunkPointer) {
    188                 next_ = chunkPointer;
    189             }
    190             const std::int64_t& LastReleaseTimeStamp() {
    191                 return lastReleaseTimeStamp_;
    192             }
    193         private:
    194             size_t AddressToIndex (void* ptr) {
    195                 return reinterpret_cast<pointer>(ptr) - data_ ;
    196             }
    197             void* IndexToAddress(const size_t& index) {
    198                 if (data_ == nullptr || index >= maxBlockCount_) {
    199                     return nullptr;
    200                 }
    201                 return data_ + index;
    202             }
    203         private:
    204             bool enabled_{false};
    205             pointer data_{nullptr};
    206             std::vector<size_t> idle_;
    207             size_t maxBlockCount_{0};
    208             size_t blockSize_{0};
    209             size_t length_{0};
    210             size_t align_{0};
    211             std::int64_t lastReleaseTimeStamp_{std::numeric_limits<std::int64_t>::max()};
    212         private:
    213             Chunk* next_{nullptr};
    214         };
    215     private:
    216         const size_t type_size_{sizeof(value_type)};
    217         const size_t align_{alignof(value_type)};
    218         const size_t minBlockSize_ {(sizeof(value_type) + alignof(value_type) - 1) / alignof(value_type) * alignof(value_type)};
    219         size_t deallocateCount_{0};
    220         Chunk* chunk_{nullptr};
    221     };
    222 
    223     // 简易对象
    224     template<typename ClassName>
    225     class MultilingualSimpleObject : public ClassName
    226     {
    227         // 不要使用虚函数,虚表会增加内存开销
    228         // 不要定义成员变量
    229         typedef MultilingualSimpleObject<ClassName> BuiltInClass;
    230     public:
    231         template<typename... T>
    232         MultilingualSimpleObject(T&&... t) : ClassName(std::forward<T>(t)...) {}
    233 //        virtual ~MultilingualSimpleObject(){}
    234 
    235         template<typename... T>
    236         static std::shared_ptr<ClassName> Create(T&&... t) {
    237             return std::shared_ptr<ClassName>(new BuiltInClass(t...));
    238         }
    239 
    240         static void* operator new(size_t size) {
    241             return Allocator<BuiltInClass>::Instance().Allocate(1);
    242         }
    243 
    244         static void operator delete (void* ptr, size_t size) {
    245             Allocator<BuiltInClass>::Instance().Deallocate(ptr, size);
    246         }
    247     };
    248 
    249 }
    250 }
  • 相关阅读:
    五大P2P平台费用一览
    警惕P2B模式
    仿照jquery封装一个自己的js库
    怎样给div增加resize事件
    美化浏览器滚动条效果
    手机端触屏手指滑动方向及拖动层
    JS中原型链中的prototype与_proto_的个人理解与详细总结(**************************************************************)
    JavaScript this用法总结(**************************************)
    js中call、apply、bind那些事2
    深刻理解JavaScript---闭包
  • 原文地址:https://www.cnblogs.com/hgwang/p/14437928.html
Copyright © 2020-2023  润新知