Skip to content

RingMem

#include <iostream>
#include <string.h>

#define ARR_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#define IN
#define OUT
#define INOUT

class RingMem {
public:
  explicit RingMem(size_t size): total_size_(size) {
    addr_ = new char[total_size_];
    if (addr_) {
      memset(addr_, 0, total_size_);
    } else {
      std::cerr << "RingMem new failed" << std::endl;
    }
  }
  ~RingMem() {
    if (addr_) {
      delete []addr_;
    }
  }

  bool is_empty() const {
    return use_ == 0 ? true : false;
  }

  bool is_full() const {
    return use_ == total_size_ ? true : false;
  }

  size_t get_value() const {
    return total_size_ - use_;
  }

  void push_data(size_t num, const char *data) {
    if (is_full()) {
      printf("addr_ is_full, push err!!!\n");
      return;
    }

    if (num > get_value()) {
      printf("push data too large, add is %ld, value is %ld\n", num, get_value());
      return;
    }

    // + is value pos
    //         0 1 2 3 4 5 6 7 8 9
    // case 1 rw + + + + + + + + +    r = w
    // case 2  r         w + + + +    r < w
    // case 3  + + + r   w + + + +    r < w
    // case 4  w + + + + r            w < r
    // case 5      w + + + r          w < r
    if (pos_w_ >= pos_r_) {
      if (total_size_ - pos_w_ >= num) {      // case 1 2
        memcpy(&addr_[pos_w_], &data[0], num);
        pos_w_ += num;
        pos_w_ %= total_size_;
      } else {                                // case 3
        size_t cpy_size_1 = total_size_ - pos_w_;
        size_t cpy_size_2 = num - cpy_size_1;
        memcpy(&addr_[pos_w_], &data[0], cpy_size_1);
        memcpy(&addr_[0], &data[cpy_size_1], cpy_size_2);
        pos_w_ = cpy_size_2;
      }
      use_ += num;
    } else if (pos_w_ < pos_r_) {             // case 4 5
      memcpy(&addr_[pos_w_], &data[0], num);
      pos_w_ += num;
      pos_w_ %= total_size_;
      use_ += num;
    } else {
      printf("push err\n");
    }
  }

  //         0 1 2 3 4 5 6 7 8 9
  // case 1 rw                      r = w
  // case 2  r + + + + w            r < w
  // case 3        r + + + w        r < w
  // case 4  w         r + + + +    w < r
  // case 5  + + w       r + + +    w < r
  void pop_data(size_t num, char *data) {
    if (num > use_) {
      printf("num>use == %ld>%ld, pop_data err!!!\n", num, use_);
      return;
    }

    if (pos_w_ >= pos_r_) {                 // case 1 2 3
      memcpy(&data[0], &addr_[pos_r_], num);
      pos_r_ += num;
      pos_r_ %= total_size_;
      use_ -= num;
    } else if (pos_w_ < pos_r_) {
      if (total_size_ - pos_r_ >= num) {    // case 4
        memcpy(&data[0], &addr_[pos_r_], num);
        pos_r_ += num;
        pos_r_ %= total_size_;
      } else {                              // case 5
        size_t cpy_size_1 = total_size_ - pos_r_;
        size_t cpy_size_2 = num - cpy_size_1;
        memcpy(&data[0], &addr_[pos_r_], cpy_size_1);
        memcpy(&data[cpy_size_1], &addr_[0], cpy_size_2);
        pos_r_ = cpy_size_2;
      }
      use_ -= num;
    } else {
      printf("pop err\n");
    }
  }

  void read_data(size_t num, char *data) {
    if (num > use_) {
      printf("num>use == %ld>%ld, read_data err!!!\n", num, use_);
      return;
    }

    if (pos_w_ >= pos_r_) {                 // case 1 2 3
      printf("[debug] read 0\n");
      memcpy(&data[0], &addr_[pos_r_], num);
    } else if (pos_w_ < pos_r_) {
      if (total_size_ - pos_r_ >= num) {    // case 4
        printf("[debug] read 1\n");
        memcpy(&data[0], &addr_[pos_r_], num);
      } else {                              // case 5
        printf("[debug] read 2\n");
        size_t cpy_size_1 = total_size_ - pos_r_;
        size_t cpy_size_2 = num - cpy_size_1;
        memcpy(&data[0], &addr_[pos_r_], cpy_size_1);
        memcpy(&data[cpy_size_1], &addr_[0], cpy_size_2);
      }
    } else {
      printf("read err\n");
    }
  }

  // for debug
  void printf_mem() {
    printf("+++++++++++++++\n");
    for (size_t i = 0; i < total_size_; i++) {
      printf("%2d ", addr_[i]);
    }
    printf("use/total: %ld/%ld", use_, total_size_);
    printf("\n");
    for (size_t i = 0; i < total_size_; i++) {
      if (pos_r_ == pos_w_) {
        printf(" rw");
        break;
      }
      if (i == pos_r_) {
        printf(" r ");
      } else if (i == pos_w_) {
        printf(" w ");
      } else {
        printf("   ");
      }
    }
    printf("\n+++++++++++++++\n");
  }

  // for debug
  bool is_same(size_t num, char *data, size_t r, size_t w, size_t use) {
    if (num != total_size_) {
      printf("num err\n");
      return false;
    }
    for (size_t i = 0; i < total_size_; i++) {
      if (addr_[i] != data[i]) {
        printf("addr_%ld err\n", i);
        return false;
      }
    }

    if (r != pos_r_) {
      printf("r err\n");
      return false;
    }
    if (w != pos_w_) {
      printf("w err\n");
      return false;
    }
    if (use != use_) {
      printf("use err\n");
      return false;
    }

    return true;
  }

  // for debug
  void set_arr(char value) {
    memset(addr_, value, total_size_);
  }
  void set_w(size_t idx) {
    pos_w_ = idx;
  }
  size_t get_w() {
    return pos_w_;
  }
  void set_r(size_t idx) {
    pos_r_ = idx;
  }
  size_t get_r() {
    return pos_r_;
  }
  void set_use(size_t idx) {
    use_ = idx;
  }
  size_t get_use() {
    return use_;
  }
  void set_r_w_user(size_t r, size_t w, size_t use) {
    pos_r_ = r;
    pos_w_ = w;
    use_ = use;
  }

private:
  char *addr_ = nullptr;
  size_t total_size_ = 0;
  size_t pos_w_ = 0;
  size_t pos_r_ = 0;
  size_t use_ = 0;
};

bool test_case_push(RingMem &ring_mem,
    size_t r1, size_t w1, size_t use1,
    char *data1, size_t len1,
    size_t r2, size_t w2, size_t use2,
    char *data2, size_t len2) {
  ring_mem.set_arr(10);
  ring_mem.set_r_w_user(r1, w1, use1);
  ring_mem.push_data(len1, data1);

  if (ring_mem.is_same(len2, data2, r2, w2, use2)) {
    return true;
  } else {
    ring_mem.printf_mem();
    std::cout << "failed:" << std::endl;
    std::cout << "should r=" << ring_mem.get_r()
              << ", w=" << ring_mem.get_w()
              << ", use=" << ring_mem.get_use()
              << std::endl;
    std::cout << "wrong  r=" << r2
              << ", w=" << w2
              << ", use=" << use2
              << std::endl;
    return false;
  }

  return true;
}

bool test_case_pop(RingMem &ring_mem,
    size_t r1, size_t w1, size_t use1,
    char *data1, size_t len1,
    size_t r2, size_t w2, size_t use2,
    char *data2, size_t len2) {
  ring_mem.set_arr(10);
  ring_mem.set_r_w_user(r1, w1, use1);
  ring_mem.pop_data(len1, data1);

  if (ring_mem.is_same(len2, data2, r2, w2, use2)) {
    return true;
  } else {
    ring_mem.printf_mem();
    std::cout << "failed:" << std::endl;
    std::cout << "should r=" << ring_mem.get_r()
              << ", w=" << ring_mem.get_w()
              << ", use=" << ring_mem.get_use()
              << std::endl;
    std::cout << "wrong  r=" << r2
              << ", w=" << w2
              << ", use=" << use2
              << std::endl;
    return false;
  }

  return true;
}


int test1() {
  char data[10] = {0};
  for (size_t i = 0; i < ARR_SIZE(data); i++) {
    data[i] = static_cast<char>(i + 20);
  }

  size_t i_count = 0;
  size_t i_success = 0;

  RingMem ring_mem(10);
  { // case 1
    std::cout << "1---------------------------" << std::endl;
    char data_ret1[10] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
    if (test_case_push(ring_mem,
        0, 0, 0, data, ARR_SIZE(data),
        0, 0, 10, data_ret1, 10) == true) {
      i_success++;
    }
    i_count++;
  }
  { // case 2
    std::cout << "2---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 20, 21, 22, 23, 24};
    if (test_case_push(ring_mem,
        0, 5, 5, data, 5,
        0, 0, 10, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // case 3
    std::cout << "3---------------------------" << std::endl;
    char data_ret1[10] = {25, 26, 27, 10, 10, 20, 21, 22, 23, 24};
    if (test_case_push(ring_mem,
        3, 5, 2, data, 8,
        3, 3, 10, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // case 4
    std::cout << "4---------------------------" << std::endl;
    char data_ret1[10] = {20, 21, 22, 23, 24, 10, 10, 10, 10, 10};
    if (test_case_push(ring_mem,
        5, 0, 5, data, 5,
        5, 5, 10, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // case 5
    std::cout << "5---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 20, 21, 22, 23, 10, 10, 10, 10};
    if (test_case_push(ring_mem,
        6, 2, 6, data, 4,
        6, 6, 10, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }

  { // pop case 1
    std::cout << "6---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
    if (test_case_pop(ring_mem,
        0, 0, 10, data, 10,
        0, 0, 0, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // pop case 2
    std::cout << "7---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
    if (test_case_pop(ring_mem,
        0, 5, 5, data, 5,
        5, 5, 0, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // pop case 3
    std::cout << "8---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
    if (test_case_pop(ring_mem,
        3, 7, 4, data, 4,
        7, 7, 0, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // pop case 4
    std::cout << "9---------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
    if (test_case_pop(ring_mem,
        5, 0, 5, data, 5,
        0, 0, 0, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }
  { // pop case 5
    std::cout << "10--------------------------" << std::endl;
    char data_ret1[10] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
    if (test_case_pop(ring_mem,
        6, 2, 6, data, 6,
        2, 2, 0, data_ret1, ARR_SIZE(data_ret1)) == true) {
      i_success++;
    }
    i_count++;
  }

  std::cout << "success[" << i_success << "/" << i_count
            << "]" << std::endl;
  return 0;
}

int test2() {
  RingMem ring_mem(10);
  char data[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'h', 'j'};  
  char data_tmp[10] = {0};

  for (size_t k = 1; k <= 10; k++) {
    size_t i_total = 100;
    size_t i_success = 0;
    size_t push_pop_size = k;
    for (size_t i = 0; i < i_total; i++) {
      memset(data_tmp, 0, 10);
      ring_mem.push_data(push_pop_size, data);
      ring_mem.pop_data(push_pop_size, data_tmp);
      size_t j = 0;
      for (j = 0; j < push_pop_size; j++) {
        if (data_tmp[j] != data[j]) {
          break;
        }
      }
      if (j == push_pop_size) {
        i_success++;
      }
    }
    std::cout << "success push_pop_size [" << push_pop_size << "]: [" << i_success << "/" << i_total
              << "]" << std::endl;
  }

  return 0;
}

// g++ test.cpp -Wall -Werror -Wextra -Wsign-conversion -Wconversion
int main() {
  test1();
  test2();

  return 0;
}