首页
社区
课程
招聘
[求助]grow_buf
发表于: 2015-8-14 20:51 1972

[求助]grow_buf

2015-8-14 20:51
1972
#ifndef _GROW_BUF_H_
#define _GROW_BUF_H_

#include "list.h"

// 地址-长度
struct addr_len {

  char *p;
  int len;
};

// 偏移-长度
struct offset_len {

  int offset;
  int len;
};

// 位置
struct position {
  
  union {
    char *p;
    int offset;
  };
  
  enum { ADDR, OFFSET } type;
};

// 位置-长度
struct pos_len {

  struct position pos;
  int len;
};

// 自动扩容缓冲区单元
struct grow_buf_unit {
  
  int offset;
  struct addr_len buf;
  
  struct list_head list;
};

// 自动扩容缓冲区
struct grow_buf {

  int default_grow;
  int size;
  int free;
  
  struct list_head head;
};

struct grow_buf *grow_buf_alloc(int size);
void grow_buf_free(struct grow_buf *buf);

int gb_read_buf(struct grow_buf *gb, struct pos_len *pos, struct addr_len *result);
int gb_write_buf(struct grow_buf *gb, struct position *pos, struct addr_len *buf, int grow);
int gb_read_file(struct grow_buf *gb, struct pos_len *pos, int fd, int offset);
int gb_write_file(struct grow_buf *gb, struct position *pos, int fd, int offset, int grow);
int gb_copy(struct grow_buf *to_gb, struct position *to_pos, 
  struct grow_buf *from_gb, struct pos_len *from_pos);

/******************************************************
 *  提供以下辅助函数:                                 *
 *  1. 方便表达"全部读取","接着空闲位置写"等含义      *
 *  2. 避免为struct pos_len *pos参数制定复杂规则      *
 ******************************************************/

// grow_buf开始位置
#define grow_buf_start(gb) ({ \
  struct grow_buf_unit *unit \
    = container_of((gb)->head.next, struct grow_buf_unit, list); \
  unit->buf.p = unit->buf.p; \
})

// grow_buf空闲位置,没有空闲位置时,返回NULL
#define grow_buf_end(gb) ({ \
  char *p = NULL; \
  if ((gb)->free > 0) { \
    struct list_head *pos, *n; \
    struct grow_buf_unit *unit; \
    list_for_each_safe(pos, n, &(gb)->head) { \
      unit = container_of((gb)->head.prev, struct grow_buf_unit, list); \
      if ((gb)->size - (gb)->free >= unit->offset \
          && (gb)->size - (gb)->free < unit->offset + unit->buf.len) { \
        p = unit->buf.p + (((gb)->size - (gb)->free) - unit->offset); \
        break; \
      } \
    } \
  } \
  p = p; \
})

// grow_buf已写入长度
#define grow_buf_write_len(gb) ((gb)->size - (gb)->free)

#endif

------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "grow-buf.h"

/*
 * grow_buf扩容
*/
static int buf_growing(struct grow_buf *buf, int grow)
{
  struct grow_buf_unit *unit = NULL;

  unit = malloc(sizeof(struct grow_buf_unit));
  if (unit == NULL) {
    printf("%s(), %d: malloc failed\n", __FUNCTION__, __LINE__);
    goto err;
  }

  unit->buf.p = malloc(grow);
  if (unit->buf.p == NULL) {
    printf("%s(), %d: malloc failed\n", __FUNCTION__, __LINE__);
    goto err;
  }

  unit->buf.len = grow;
  unit->offset = buf->size;

  list_add_tail(&unit->list, &buf->head);
  
  buf->size += unit->buf.len;
  buf->free += unit->buf.len;
  
  printf("%s(), %d: grew successed, %d -> %p\n", __FUNCTION__, __LINE__, grow, unit->buf.p);
  
  return 0;
err:
  if (unit != NULL) {
    if (unit->buf.p != NULL)
      free(unit->buf.p);
    free(unit);
  }
  return -1;
}

/*
 * 通过地址查找unit
*/
#define gb_unit_by_addr(gb, addr) ({ \
  struct list_head *_pos, *_n; \
  struct grow_buf_unit *unit; \
  list_for_each_safe(_pos, _n, &(gb)->head) { \
    unit = container_of(_pos, struct grow_buf_unit, list); \
    if ((addr) >= unit->buf.p && (addr) < unit->buf.p+unit->buf.len) \
      break; \
  } \
  if (_pos == &(gb)->head) \
    unit = NULL; \
  unit = unit; \
})
/*
 * 通过偏移查找unit
*/
#define gb_unit_by_offset(gb, _offset) ({ \
  struct list_head *_pos, *_n; \
  struct grow_buf_unit *unit; \
  list_for_each_safe(_pos, _n, &(gb)->head) { \
    unit = container_of(_pos, struct grow_buf_unit, list); \
    if ((_offset) >= unit->offset && (_offset) < unit->offset+unit->buf.len) \
      break; \
  } \
  if (_pos == &(gb)->head) \
    unit = NULL; \
  unit = unit; \
})

/*
 * grow_buf分配
 *
 * size: 初始化大小,同时也作为默认增长大小
*/
struct grow_buf *grow_buf_alloc(int size)
{
  struct grow_buf *gb = NULL;

  gb = malloc(sizeof(struct grow_buf));
  if (gb == NULL) {
    printf("%s(), %d: malloc failed\n", __FUNCTION__, __LINE__);
    goto err;
  }

  gb->default_grow = size;
  gb->size = 0;
  gb->free = 0;
  
  INIT_LIST_HEAD(&gb->head);
  
  if (buf_growing(gb, size) < 0)
    goto err;

  return gb;
err:
  grow_buf_free(gb);
  return NULL;
}

/*
 * grow_buf释放
*/
void grow_buf_free(struct grow_buf *buf)
{
  if (buf != NULL)
  {
    struct list_head *_pos, *_n;
    struct grow_buf_unit *unit;

    list_for_each_safe(_pos, _n, &buf->head)
    {
      unit = container_of(_pos, struct grow_buf_unit, list);
      list_del_init(&unit->list);

      if (unit->buf.p != NULL)
        free(unit->buf.p);
      free(unit);
    }

    free(buf);
  }
}

/*
 * grow_buf读取,如果读取的数据跨越unit,需要读取多次,直到pos->len=0
 *
 * pos: 读取位置,程序执行后,会将其更新为下次要读的位置和长度
 * result: 读取结果
*/
int gb_read_buf(struct grow_buf *gb, struct pos_len *pos, struct addr_len *result)
{
  struct grow_buf_unit *unit = NULL;

  if (pos->len == 0) {
    result->p = NULL;
    result->len = 0;
    return 0;
  }

  if (pos->len < 0)
    return -1;

  switch (pos->pos.type)
  {
  case ADDR:
    if (pos->pos.p == NULL)
      return -1;
    unit = gb_unit_by_addr(gb, pos->pos.p);
    break;
  case OFFSET:
    if (pos->pos.offset < 0)
      return -1;
    unit = gb_unit_by_offset(gb, pos->pos.offset);
    pos->pos.type = ADDR;
    pos->pos.p = unit->buf.p + (pos->pos.offset - unit->offset);
    break;
  default:
    break;
  }

  if (unit == NULL || grow_buf_write_len(gb) 
      - (unit->offset + (pos->pos.p - unit->buf.p)) < pos->len)
  {
    printf("%s(), %d: beyond grow_buf scope\n", __FUNCTION__, __LINE__);
    return -1;
  }

  result->p = pos->pos.p;

  if ((result->len = (unit->buf.p 
    + unit->buf.len)-pos->pos.p) <= pos->len)
  {
    unit = container_of(unit->list.next, struct grow_buf_unit, list);
    pos->pos.p = unit->buf.p;
  } else {
    result->len = pos->len;
    pos->pos.p += result->len;
  }

  pos->len -= result->len;
  
  return result->len;
}

/*
 * grow_buf写入
 *
 * pos:  写入位置 (pos->p=NULL,可能由于无空闲空间导致)
 * buf:  希望写入的数据
 * grow: 当gb剩余空间不足时,希望增长的大小 (<=0表示按默认大小增长)
 *       最终增长大小,根据grow,default_grow,buf->len确定
*/
int gb_write_buf(struct grow_buf *gb, struct position *pos, struct addr_len *buf, int grow)
{
  struct grow_buf_unit *unit = NULL;
  int offset = 0, _offset = 0;
  int len = buf->len;

  if (buf->len == 0)
    return 0;

  if (buf->len < 0)
    return -1;
  
  if (grow <= 0)
    grow = gb->default_grow;
  
  switch (pos->type)
  {
  case ADDR:
    if (pos->p != NULL) {
      if ((unit = gb_unit_by_addr(gb, pos->p)) == NULL)
        return -1;
      offset = pos->p - unit->buf.p;
    } else {
      if (gb->free > 0)
        return -1;
      printf("%s(), %d: !!!!!!!!!!!!!!!!!!!!!!\n", __FUNCTION__, __LINE__);
      grow = grow < buf->len ? buf->len : grow;
      if (buf_growing(gb, grow) < 0)
        return -1;
      unit = container_of(gb->head.prev, struct grow_buf_unit, list);
      offset = 0;
    }
    break;
  case OFFSET:
    if (pos->offset < 0)
      return -1;
    if ((unit = gb_unit_by_offset(gb, pos->offset)) == NULL)
    {
      printf("%s(), %d: !!!!!!!!!!!!!!!!!!!!!!\n", __FUNCTION__, __LINE__);
      grow = grow < (pos->offset - gb->size + buf->len) ?
        (pos->offset - gb->size + buf->len) : grow;
      if (buf_growing(gb, grow) < 0)
        return -1;
      unit = container_of(gb->head.prev, struct grow_buf_unit, list);
    }
    offset = pos->offset - unit->offset;
    break;
  default:
    printf("%s(), %d: wrong position type !\n", __FUNCTION__, __LINE__);
    return -1;
  }

  while (1)
  {
    int _len = (unit->offset+unit->buf.len)-offset;

    if (_len > len)
      _len = len;
    
    printf("write: %p, len: %d\n", unit->buf.p+offset, _len);
    printf("%d, %d\n", offset, _offset);
    
    memcpy(unit->buf.p+offset, buf->p+_offset, _len);
    
    _offset += _len;
    if (unit->offset+offset+_len > grow_buf_write_len(gb))
      gb->free -= (unit->offset+offset+_len - grow_buf_write_len(gb));
    
    if ((len -= _len) == 0)
      break;

    if (buf_growing(gb, grow < len ? len : grow) < 0)
      return -1;
    
    unit = container_of(unit->list.next, struct grow_buf_unit, list);
    offset = 0;
  }

  return 0;
}

/*
 * 读取grow_buf数据到文件
 *
 * pos: 读取位置
 * offset: 文件偏移
*/
int gb_read_file(struct grow_buf *gb, struct pos_len *pos, int fd, int offset)
{
  return 0;
}

/*
 * 将文件数据写入grow_buf
 *
 * pos: 写入位置 (NULL表示空闲空间开始位置)
 * offset: 文件偏移
 * grow: 当gb剩余空间不足时,希望增长的大小 (0表示按默认大小增长)
*/
int gb_write_file(struct grow_buf *gb, struct position *pos, int fd, int offset, int grow)
{
  return 0;
}

/*
 * grow_buf之间数据复制
 * 
 * to_pos: 写入位置 (NULL表示空闲空间开始位置)
 * pos:    读取位置
*/
int gb_copy(struct grow_buf *to_gb, struct position *to_pos, 
  struct grow_buf *from_gb, struct pos_len *from_pos)
{
  return 0;
}

int main()
{
  struct grow_buf *gb = NULL;
  struct position pos;
  struct addr_len buf;
  struct pos_len _pos;
  int i, ret;

  gb = grow_buf_alloc(128);
  if (gb == NULL)
    goto err;

  // write
  buf.p = "0123456789";
  buf.len = 10;
  
  for (i = 0; i < 15; i ++)
  {
    pos.type = ADDR;
    pos.p = grow_buf_end(gb);
    //pos.type = OFFSET;
    //pos.offset = buf.len * i;
    
    ret = gb_write_buf(gb, &pos, &buf, 0);
    if (ret < 0)
      goto err;
  }

  // read
  //_pos.pos.type = ADDR;
  //_pos.pos.p = grow_buf_start(gb);
  _pos.pos.type = OFFSET;
  _pos.pos.p = 0;
  _pos.len = 140;
  
  while (1)
  {
    ret = gb_read_buf(gb, &_pos, &buf);
    if (ret < 0)
      goto err;
    
    printf("%d\n", buf.len);
    printf("%s\n", buf.p);
    if (_pos.len == 0)
      break;
  }

  grow_buf_free(gb);
  
  return 0;
err:
  grow_buf_free(gb);
  return -1;
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//