C语言实现一个先进先出的队列

代码来源silicon labs的sdk。

一 源码

app_queue.h

#ifndef APP_QUEUE_H
#define APP_QUEUE_H

#include <stdint.h>
#include <stdbool.h>


typedef enum{
	QUEUE_STATUS_OK,                 /**< successful.           */
	QUEUE_STATUS_NULL_POINTER,       /**< Invalid pointer.      */
	QUEUE_STATUS_NOT_INITIALIZED,    /**< not initialized.      */
	QUEUE_STATUS_WOULD_OVERFLOW,     /**< Queue would overflow. */
	QUEUE_STATUS_EMPTY,              /**< queue is empty.       */
}queue_status_t;

//Implement critical protection according to the platform
#define CORE_DECLARE_IRQ_STATE
#define CORE_ENTER_CRITICAL()
#define CORE_EXIT_CRITICAL()

// -----------------------------------------------------------------------------
// Structures and Types

/// Application Queue pointer type forward declaration
typedef struct app_queue *app_queue_ptr_t;

/***************************************************************************//**
 * Prototype of queue overflow callback function.
 *
 * @param[in] queue Pointer to the queue structure being overflowed.
 * @param[in] data  Pointer to the item being considered for removal from
 *                  the queue on overflow.
 *
 * @retval true     Discard the queue item being considered for removal
 *                  (default behavior).
 * @retval false    Nothing to be discarded from the queue.
 ******************************************************************************/
typedef bool (*app_queue_overflow_callback_t)(app_queue_ptr_t queue, \
                                              uint8_t         *data);

/// Application Queue structure
typedef struct app_queue {
  uint16_t                      head;      ///< Head position
  uint16_t                      count;     ///< Count of items in the list
  uint16_t                      size;      ///< Size of the queue
  uint16_t                      item_size; ///< Size of one queue item
  app_queue_overflow_callback_t callback;  ///< Overflow callback
  uint8_t                       *data;     ///< Data storage for the queue
} app_queue_t;

/***************************************************************************//**
 * Static allocation macro
 *
 * @param[in] HANDLE Handle name of the queue.
 * @param[in] TYPE   Base element type of the queue
 * @param[in] SIZE   Requested size of the queue in elements.
 ******************************************************************************/
#define APP_QUEUE(HANDLE, TYPE, SIZE) \
  app_queue_t HANDLE;                 \
  static TYPE HANDLE##_data[SIZE]

/***************************************************************************//**
 * Initialization macro
 *
 * @param[in] HANDLE Handle name of the queue.
 * @param[in] TYPE   Base element type of the queue
 * @param[in] SIZE   Requested size of the queue in elements.
 *
 * @retval QUEUE_STATUS_OK           Initialization was successful.
 * @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
 ******************************************************************************/
#define APP_QUEUE_INIT(HANDLE, TYPE, SIZE) \
  app_queue_init(HANDLE, SIZE, sizeof(TYPE), (void *)HANDLE##_data)

// -----------------------------------------------------------------------------
// Queue Functions

/***************************************************************************//**
 * Initialize the queue.
 *
 * @param[in] queue     Pointer to the queue structure to initialize.
 * @param[in] size      The number of entries to store in this queue
 * @param[in] item_size The size of a queue element.
 * @param[in] data      Pointer to the data storage.
 *
 * @retval QUEUE_STATUS_OK           Initialization was successful.
 * @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
 ******************************************************************************/
queue_status_t app_queue_init(app_queue_t *queue,
                           uint16_t    size,
                           uint16_t    item_size,
                           uint8_t     *data);

/***************************************************************************//**
 * Add item to the end of the queue.
 *
 * If the queue is full, the oldest queued item will be replaced by default.
 * Register an overflow callback to change this default behavior.
 *
 * @param[in] queue The queue to add the item to.
 * @param[in] data  The pointer object to store in the queue.
 *
 * @retval QUEUE_STATUS_OK              Adding item was successful.
 * @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
 * @retval QUEUE_STATUS_WOULD_OVERFLOW  Queue would overflow and the overflow event
 *                                   was not handled.
 * @retval QUEUE_STATUS_NULL_POINTER    Pointer to the queue or data is invalid.
 ******************************************************************************/
queue_status_t app_queue_add(app_queue_t *queue, uint8_t *data);

/***************************************************************************//**
 * Specify a callback to be called upon queue overflow.
 *
 * The oldest queued item being considered for removal on queue overflow is
 * provided by this callback.
 *
 * @param[in] queue     The queue to specify an overflow callback for.
 * @param[in] callback  The callback to be called on queue overflow. If callback
 *                      is NULL, no callback will be issued on queue overflow.
 *
 * @retval QUEUE_STATUS_OK           Setting callback was successful.
 * @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue is invalid.
 ******************************************************************************/
queue_status_t app_queue_set_overflow_callback(app_queue_t                   *queue,
                                            app_queue_overflow_callback_t callback);

/***************************************************************************//**
 * Get a pointer to the head of the queue without removing that item.
 *
 * @param[in]  queue The queue to peek at the item from.
 * @param[out] data  Data output for the item to copy into.
 *
 * @retval QUEUE_STATUS_OK              Getting item was successful.
 * @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
 * @retval QUEUE_STATUS_EMPTY           Queue is empty.
 * @retval QUEUE_STATUS_NULL_POINTER    Pointer to the queue or data is invalid.
 ******************************************************************************/

queue_status_t app_queue_peek(app_queue_t *queue, uint8_t *data);

/***************************************************************************//**
 * Remove an item from the head of the queue and return its data pointer.
 *
 * @param[in]  queue The queue to remove the item from.
 * @param[out] data  Data output for the item to copy into.
 *
 * @retval QUEUE_STATUS_OK              Removing item was successful.
 * @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
 * @retval QUEUE_STATUS_EMPTY           Queue is empty.
 * @retval QUEUE_STATUS_NULL_POINTER    Pointer to the queue or data is invalid.
 ******************************************************************************/
queue_status_t app_queue_remove(app_queue_t *queue, uint8_t *data);

/***************************************************************************//**
 * Determine if the given queue is empty.
 *
 * @param[in]  queue The queue to check the status of.
 *
 * @return     True, if the queue is empty.
 ******************************************************************************/
bool app_queue_is_empty(app_queue_t *queue);

/***************************************************************************//**
 * Determine if the given queue is full.
 *
 * @param[in]  queue The queue to check the status of.
 *
 * @return     True, if the queue is full.
 ******************************************************************************/
bool app_queue_is_full(app_queue_t *queue);

#endif // APP_QUEUE_H

app_queue.c


#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "app_queue.h"


// -----------------------------------------------------------------------------
// Public functions

queue_status_t app_queue_init(app_queue_t *queue,
                              uint16_t    size,
                              uint16_t    item_size,
                              uint8_t     *data)
{
  if (queue == NULL || data == NULL) {
    return QUEUE_STATUS_NULL_POINTER;
  }
  // Atomically initialize the queue structure
  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  queue->item_size = item_size;
  queue->data = data;
  queue->size = size;
  queue->head = 0;
  queue->count = 0;
  queue->callback = NULL;
  CORE_EXIT_CRITICAL();

  return QUEUE_STATUS_OK;
}

queue_status_t app_queue_set_overflow_callback(app_queue_t                   *queue,
                                               app_queue_overflow_callback_t callback)
{
  if (queue == NULL) {
    return QUEUE_STATUS_NULL_POINTER;
  }
  queue->callback = callback;
  return QUEUE_STATUS_OK;
}

queue_status_t app_queue_add(app_queue_t *queue, uint8_t *data)
{
  queue_status_t sc = QUEUE_STATUS_OK;
  bool added = false;
  // Do nothing if there's no queue or data given
  if (queue == NULL || data == NULL) {
    return QUEUE_STATUS_NULL_POINTER;
  }
  if (queue->data == NULL) {
    return QUEUE_STATUS_NOT_INITIALIZED;
  }


  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  if (queue->count < queue->size) {
    uint16_t offset = (queue->head + queue->count) % queue->size;

    // Insert this item at the end of the queue
    uint8_t *ptr = queue->data + (offset * queue->item_size);
    memcpy(ptr, data, queue->item_size);
    queue->count++;
    added = true;
  } else {
    // If an overflow callback exists, call it to see if the oldest queued
    // item is to be replaced (default) or not.
    uint8_t *ptr = (queue->data + (queue->head * queue->item_size));
    if (queue->callback != NULL) {
      added = queue->callback(queue, ptr);
    } else {
      // There is no callback set, queue would overflow
      sc = QUEUE_STATUS_WOULD_OVERFLOW;
    }
    // Overwrite what's at the head of the queue since we're out of space
    if (added) {
      memcpy(ptr, data, queue->item_size);
      queue->head = (queue->head + 1) % queue->size;
    }
  }
  CORE_EXIT_CRITICAL();

  return sc;
}

queue_status_t app_queue_peek(app_queue_t *queue, uint8_t * data)
{
  queue_status_t sc = QUEUE_STATUS_OK;
  uint8_t *ptr = NULL;

  // Do nothing if there's no queue or data given
  if (queue == NULL || data == NULL) {
    return QUEUE_STATUS_NULL_POINTER;
  }
  if (queue->data == NULL) {
    return QUEUE_STATUS_NOT_INITIALIZED;
  }

  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  if (queue->count > 0) {
    ptr = (queue->data + (queue->head * queue->item_size));
    memcpy(data, ptr, queue->item_size);
  } else {
    sc = QUEUE_STATUS_EMPTY;
  }
  CORE_EXIT_CRITICAL();

  return sc;
}

queue_status_t app_queue_remove(app_queue_t *queue, uint8_t * data)
{
  queue_status_t sc = QUEUE_STATUS_OK;
  uint8_t *ptr = NULL;

  // Do nothing if there's no queue or data given
  if (queue == NULL || data == NULL) {
    return QUEUE_STATUS_NULL_POINTER;
  }
  if (queue->data == NULL) {
    return QUEUE_STATUS_NOT_INITIALIZED;
  }

  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  if (queue->count > 0) {
    ptr = (queue->data + queue->head * queue->item_size);
    memcpy(data, ptr, queue->item_size);
    queue->head = (queue->head + 1) % queue->size;
    queue->count--;
  } else {
    sc = QUEUE_STATUS_EMPTY;
  }
  CORE_EXIT_CRITICAL();

  return sc;
}

bool app_queue_is_empty(app_queue_t *queue)
{
  bool result;

  // Do nothing if there's no queue or output given
  if (queue == NULL) {
    return true;
  }
  if (queue->data == NULL) {
    return true;
  }

  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  result = (queue->count == 0);
  CORE_EXIT_CRITICAL();

  return result;
}

bool app_queue_is_full(app_queue_t *queue)
{
  bool result;

  // Do nothing if there's no queue or output given
  if (queue == NULL) {
    return false;
  }
  if (queue->data == NULL) {
    return false;
  }

  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();
  result = (queue->count == queue->size);
  CORE_EXIT_CRITICAL();

  return result;
}

二 用法

unit_test.h

#include <stdint.h>

typedef struct __attribute__((__packed__))
{
  uint16_t size;
  uint8_t age;
}unit_payload_t;

void unit_init_queue(void);
void unit_print_queue(void);

unit_test.c

#include "app_queue.h"
#include "unit.h"
#include "app_log.h"

#define UNIT_QUEUE_SIZE 5

//定义了一个队列,名字为unit_queue, 队列中存放的数据类型为unit_payload_t,一共可以存放UNIT_QUEUE_SIZE
APP_QUEUE(unit_queue, unit_payload_t, UNIT_QUEUE_SIZE);

app_queue_t* p_unit_queue = &unit_queue;

//队列溢出时处理方法,返回true表示覆盖最早的数据,返回false表示不覆盖
bool unit_queue_overflow_callback(app_queue_ptr_t queue, uint8_t *data)
{
  (void)queue;
  (void)data;

  return true;
}

//初始化队列
void unit_init_queue(void)
{
  APP_QUEUE_INIT(&unit_queue, unit_payload_t, UNIT_QUEUE_SIZE);
  
  //设置队列的溢出回调函数
  app_queue_set_overflow_callback(p_unit_queue, unit_queue_overflow_callback);

  //给队列赋值
  for(int i = 0; i < 6; i++){
      unit_payload_t payload;
      payload.size = i;
      payload.age = i * 10;

      app_queue_add(p_unit_queue, (uint8_t*)&payload);
  }
}

void unit_print_queue(void)
{
  while(app_queue_is_empty(p_unit_queue) == false){
      unit_payload_t payload;

      if(app_queue_remove(p_unit_queue, (uint8_t*)&payload) == SL_STATUS_OK){
          app_log_debug("size: %d, age: %d\n", payload.size, payload.age);
      }else{
          app_log_debug("queue remote failed\n");
      }

  }
}

main.c

void main(void)
{
	unit_init_queue();

	unit_print_queue();
}

打印结果:

size: 1, age: 10 
size: 2, age: 20 
size: 3, age: 30 
size: 4, age: 40 
size: 5, age: 50 

如果函数unit_queue_overflow_callback返回false,打印结果为

size: 0, age: 0
size: 1, age: 10 
size: 2, age: 20 
size: 3, age: 30 
size: 4, age: 40 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值