#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;
}