text: #include "easy_pool.h"
  #include "easy_log.h"
  #include "easy_mod_stat.h"
  #include <assert.h>
  #include <stdio.h>
  
  static void *easy_pool_alloc_block(easy_pool_t *pool, uint32_t size);
  static void *easy_pool_alloc_large(easy_pool_t *pool, easy_pool_large_t *large, uint32_t size);
  easy_pool_realloc_pt    easy_pool_realloc = easy_pool_default_realloc;
  #define EASY_POOL_LOCK(pool) int kcolt = pool->flags; if (unlikely(kcolt)) easy_spin_lock(&pool->tlock);
  #define EASY_POOL_UNLOCK(pool) if (unlikely(kcolt)) easy_spin_unlock(&pool->tlock);
  
  easy_pool_t *easy_pool_create(uint32_t size)
  {
      easy_pool_t             *p;
  
      size = easy_align(size + sizeof(easy_pool_t), EASY_POOL_ALIGNMENT);
  
      if ((p = (easy_pool_t *)easy_pool_realloc(NULL, size)) == NULL)
          return NULL;
  
      memset(p, 0, sizeof(easy_pool_t));
      p->last = (uint8_t *) p + sizeof(easy_pool_t);
      p->end = (uint8_t *) p + size;
      p->max = size - sizeof(easy_pool_t);
      p->current = p;
      p->mod_stat = easy_cur_mod_stat;
  #ifdef EASY_DEBUG_MAGIC
      p->magic = EASY_DEBUG_MAGIC_POOL;
  #endif
  
      return p;
  }
  
  // clear
  void easy_pool_clear(easy_pool_t *pool)
  {
      easy_pool_t             *p, *n;
      easy_pool_large_t       *l;
      easy_pool_cleanup_t     *cl;
  
      // cleanup
      for (cl = pool->cleanup; cl; cl = cl->next) {
          if (cl->handler)(*cl->handler)(cl->data);
      }
  
      // large
      for (l = pool->large; l; l = l->next) {
          easy_pool_realloc(l->data, 0);
      }
  
      // other page
      for (p = pool->next; p; p = n) {
          n = p->next;
          easy_pool_realloc(p, 0);
      }
  
      pool->cleanup = NULL;
      pool->large = NULL;
      pool->next = NULL;
      pool->current = pool;
      pool->failed = 0;
      pool->last = (uint8_t *) pool + sizeof(easy_pool_t);
  }
  
  void easy_pool_destroy(easy_pool_t *pool)
  {
      EASY_STAT_TIME_GUARD((ev_malloc_count++, ev_malloc_time += cost), "easy_pool_destroy");
      easy_pool_clear(pool);
      assert(pool->ref == 0);
  #ifdef EASY_DEBUG_MAGIC
      pool->magic ++;
  #endif
      easy_pool_realloc(pool, 0);
  }
  
  void *easy_pool_alloc_ex(easy_pool_t *pool, uint32_t size, int align)
  {
      EASY_STAT_TIME_GUARD((ev_malloc_count++, ev_malloc_time += cost), "easy_pool_alloc: size=%d", size);
      uint8_t                 *m;
      easy_pool_t             *p;
      int                     dsize;
  
      // init
      dsize = 0;
  
      if (size > pool->max) {
          dsize = size;
          size = sizeof(easy_pool_large_t);
      }
  
      EASY_POOL_LOCK(pool);
  
      p = pool->current;
  
      do {
          m = easy_align_ptr(p->last, align);
  
          if (m + size <= p->end) {
              p->last = m + size;
              break;
          }
  
          p = p->next;
      } while (p);
  
      easy_cur_mod_stat = pool->mod_stat;
      if (p == NULL) {
          m = (uint8_t *)easy_pool_alloc_block(pool, size);
      }
  
      if (m && dsize) {
          m = (uint8_t *)easy_pool_alloc_large(pool, (easy_pool_large_t *)m, dsize);
      }
      easy_cur_mod_stat = NULL;
  
      EASY_POOL_UNLOCK(pool);
  
      return m;
  }
  
  void *easy_pool_calloc(easy_pool_t *pool, uint32_t size)
  {
      void                    *p;
  
      if ((p = easy_pool_alloc_ex(pool, size, sizeof(long))) != NULL)
          memset(p, 0, size);
  
      return p;
  }
  
  // set lock
  void easy_pool_set_lock(easy_pool_t *pool)
  {
      pool->flags = 1;
  }
  
  // set realloc
  void easy_pool_set_allocator(easy_pool_realloc_pt alloc)
  {
      easy_pool_realloc = (alloc ? alloc : easy_pool_default_realloc);
      realloc_lowlevel = easy_pool_realloc;
      easy_pool_realloc = realloc_with_mod_stat;
  }
  
  void *easy_pool_default_realloc(void *ptr, size_t size)
  {
      if (size) {
          return realloc(ptr, size);
      } else if (ptr) {
          //free(ptr);
      }
  
      return 0;
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  // default realloc
  
  static void *easy_pool_alloc_block(easy_pool_t *pool, uint32_t size)
  {
      uint8_t                 *m;
      uint32_t                psize;
      easy_pool_t             *p, *newpool, *current;
  
      psize = (uint32_t)(pool->end - (uint8_t *) pool);
  
      if ((m = (uint8_t *)easy_pool_realloc(NULL, psize)) == NULL)
          return NULL;
  
      newpool = (easy_pool_t *) m;
      newpool->end = m + psize;
      newpool->next = NULL;
      newpool->failed = 0;
  
      m += offsetof(easy_pool_t, current);
      m = easy_align_ptr(m, sizeof(unsigned long));
      newpool->last = m + size;
      current = pool->current;
  
      for (p = current; p->next; p = p->next) {
          if (p->failed++ > 4) {
              current = p->next;
          }
      }
  
      p->next = newpool;
      pool->current = current ? current : newpool;
  
      return m;
  }
  
  static void *easy_pool_alloc_large(easy_pool_t *pool, easy_pool_large_t *large, uint32_t size)
  {
      if ((large->data = (uint8_t *)easy_pool_realloc(NULL, size)) == NULL)
          return NULL;
  
      large->next = pool->large;
      large->size = size;
      pool->large = large;
      return large->data;
  }
  
  /**
   * strdup
   */
  char *easy_pool_strdup(easy_pool_t *pool, const char *str)
  {
      int                     sz;
      char                    *ptr;
  
      if (str == NULL)
          return NULL;
  
      sz = strlen(str) + 1;
  
      if ((ptr = (char *)easy_pool_alloc(pool, sz)) == NULL)
          return NULL;
  
      memcpy(ptr, str, sz);
      return ptr;
  }
  
  easy_pool_cleanup_t *easy_pool_cleanup_new(easy_pool_t *pool, const void *data, easy_pool_cleanup_pt *handler)
  {
      easy_pool_cleanup_t *cl;
      cl = easy_pool_alloc(pool, sizeof(easy_pool_t));
  
      if (cl) {
          cl->handler = handler;
          cl->data = data;
      }
  
      return cl;
  }
  
  void easy_pool_cleanup_reg(easy_pool_t *pool, easy_pool_cleanup_t *cl)
  {
      EASY_POOL_LOCK(pool);
      cl->next = pool->cleanup;
      pool->cleanup = cl;
      EASY_POOL_UNLOCK(pool);
  }
  
  