/*
 * Two Levels Segregate Fit memory allocator (TLSF)
 * Version 1.3
 *
 * Written by Miguel Masmano Tello <mmasmano@disca.upv.es>
 *
 * Thanks to Ismael Ripoll for his suggestions and reviews
 *
 * Copyright (C) April 2004 UPVLC, OCERA Consortium
 * 
 * This code is released using a dual license strategy: GPL/LGPL
 * You can choose the license that better fits your requirements.
 *
 * Released under the terms of the GNU General Public License Version 2.0
 * Released under the terms of the GNU Lesser General Public License Version 2.1
 *
 */

#ifndef _TLSF_STRUCT_FUNCTIONS_H_
#define _TLSF_STRUCT_FUNCTIONS_H_

#include "TLSF_def.h"

/* This code  is used to initialise  and to insert a  new block header
   into  the TLSF  structure by  rtl_malloc,  rtl_free, add_free_block
   functions
*/

static inline void init_and_insert_block (TLSF_t *ptr_TLSF, 
					  block_header_t *bh, 
					  int fl, int sl) {
  bh -> ptr.free_ptr.first_index = fl;
  bh -> ptr.free_ptr.second_index = sl;
  bh -> ptr.free_ptr.prev = NULL;
  bh -> ptr.free_ptr.next = ptr_TLSF -> fl_array [fl].sl_array [sl];
  if (ptr_TLSF -> fl_array [fl].sl_array [sl]) {
#ifdef SANITY_CHECK
    check_range_bh (bh -> ptr.free_ptr.next, "i_i 1");
    check_mn (bh -> ptr.free_ptr.next, "i_i 1");
#endif
    ptr_TLSF -> fl_array [fl].sl_array [sl] -> ptr.free_ptr.prev = bh;
  }
  ptr_TLSF -> fl_array [fl].sl_array [sl] = bh;
#ifdef SANITY_CHECK
  check_range_bh (bh, "i_i 1");
  check_mn (bh, "i_i 1");
#endif
  TLSF__set_bit (sl, ptr_TLSF -> fl_array[fl].bitmapSL);
  TLSF__set_bit (fl, ptr_TLSF -> bitmapFL);
}

static inline void init_and_insert_small_block (TLSF_t *ptr_TLSF, 
						block_header_t *bh, 
						int fl) {
  bh -> ptr.free_ptr.prev = NULL;
  bh -> ptr.free_ptr.next = ptr_TLSF -> small_blocks_array [fl];
  if (ptr_TLSF -> small_blocks_array [fl])
    ptr_TLSF -> small_blocks_array [fl] -> ptr.free_ptr.prev = bh;
  
  ptr_TLSF -> small_blocks_array [fl] = bh;
  TLSF__set_bit (fl, ptr_TLSF -> small_blocks_bitmap); 
}

static inline void remove_small_block (block_header_t *bh, 
				       TLSF_t *ptr_TLSF) {
  __s32 fl = GET_BLOCK_SIZE (bh) - 2;
  
  /* we are lucky, we can merge bh with the following one */  
  if (bh -> ptr.free_ptr.next)
    bh -> ptr.free_ptr.next -> ptr.free_ptr.prev =
      bh  -> ptr.free_ptr.prev;
  
  if (bh -> ptr.free_ptr.prev)
    bh -> ptr.free_ptr.prev -> ptr.free_ptr.next =
      bh -> ptr.free_ptr.next;
  
  /* bh must be deleted from fl_array */
  if (ptr_TLSF -> small_blocks_array [fl] == bh)
    ptr_TLSF -> small_blocks_array [fl] = bh -> ptr.free_ptr.next;

  if (!ptr_TLSF -> small_blocks_array [fl])
    TLSF__clear_bit (fl, ptr_TLSF -> small_blocks_bitmap); 
}

/* Following function merges a given block with the TLSF structure */
static inline void remove_block (block_header_t *bh2, TLSF_t *ptr_TLSF) {
  
  __s32 fl, sl;

  /* we are lucky, we can merge bh with the following one */  
  if (bh2 -> ptr.free_ptr.next)
    bh2 -> ptr.free_ptr.next -> ptr.free_ptr.prev =
      bh2  -> ptr.free_ptr.prev;
  
  if (bh2 -> ptr.free_ptr.prev)
    bh2 -> ptr.free_ptr.prev -> ptr.free_ptr.next =
      bh2 -> ptr.free_ptr.next;
  
  fl = bh2 -> ptr.free_ptr.first_index;
  sl = bh2 -> ptr.free_ptr.second_index;
  
#ifdef SANITY_CHECK
  check_fl_sl_2 (fl, sl, ptr_TLSF, "r_b 1");
#endif
  
  /* bh2 must be deleted from fl_array */
  if (ptr_TLSF -> fl_array [fl].sl_array [sl] == bh2) {
    ptr_TLSF -> fl_array [fl].sl_array [sl] = bh2 -> ptr.free_ptr.next;
#ifdef SANITY_CHECK
    if (ptr_TLSF -> fl_array [fl].sl_array [sl]) {
      check_range_bh (ptr_TLSF -> fl_array [fl].sl_array [sl], "r_b 1");
      check_mn (ptr_TLSF -> fl_array [fl].sl_array [sl], "r_b 1");
    }
#endif
  }
  if (!ptr_TLSF -> fl_array [fl].sl_array [sl]) {
    TLSF__clear_bit (sl, ptr_TLSF -> fl_array[fl].bitmapSL);
    if (!ptr_TLSF -> fl_array[fl].bitmapSL)
      TLSF__clear_bit (fl, ptr_TLSF -> bitmapFL);
  }
}

#endif
