1 /* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef RINGBUFFER_H 17 #define RINGBUFFER_H 18 19 #include <mutex> 20 #include <securec.h> 21 22 class RingBuffer { 23 public: 24 enum MemAlignShift:std::size_t { 25 B_ALIGN_SHIFT = 0, // byte alingment 26 H_ALIGN_SHIFT = 1, // half word alignment 27 W_ALIGN_SHIFT = 2, // word alignment 28 D_ALIGN_SHIFT = 3, // double word alignment 29 }; 30 31 RingBuffer( 32 const std::size_t bufSize = DEFAULT_SIZE, 33 const enum MemAlignShift shift = B_ALIGN_SHIFT); 34 ~RingBuffer()35 inline ~RingBuffer() 36 { 37 if (buffer_ != nullptr) { 38 delete[] buffer_; 39 buffer_ = nullptr; 40 } 41 } 42 inline operator bool() 43 { 44 std::lock_guard<std::mutex> lk {mtx_}; 45 return buffer_; 46 } GetFreeSize()47 inline std::size_t GetFreeSize() 48 { 49 std::lock_guard<std::mutex> lk {mtx_}; 50 return FreeSize(); 51 } GetDataSize()52 inline std::size_t GetDataSize() 53 { 54 std::lock_guard<std::mutex> lk {mtx_}; 55 return DataSize(); 56 } GetCapacity()57 inline std::size_t GetCapacity() 58 { 59 std::lock_guard<std::mutex> lk {mtx_}; 60 return Capacity(); 61 } 62 template<typename T> Peek(T * var)63 int Peek(T *var) 64 { 65 const std::size_t len {sizeof(T)}; 66 char *dest = reinterpret_cast<char*>(var); 67 if (dest == nullptr) { 68 return -1; 69 } 70 if (len == 0) { 71 return -1; 72 } 73 std::lock_guard<std::mutex> lk {mtx_}; 74 auto dataSize = DataSize(); 75 if (dataSize < len) { 76 return -1; 77 } 78 if (head_ + len > bufSize_) { 79 // data splitted 80 int ret = memcpy_s(dest, len, buffer_ + head_, bufSize_ - head_); 81 if (ret != EOK) { 82 return -1; 83 } 84 ret = memcpy_s(dest + bufSize_ - head_, len + head_ - bufSize_, buffer_, len + head_ - bufSize_); 85 if (ret != EOK) { 86 return -1; 87 } 88 } else { 89 if (memcpy_s(dest, len, buffer_ + head_, len) != EOK) { 90 return -1; 91 } 92 } 93 return 0; 94 } 95 96 ssize_t Read(const int fd, const std::size_t len); 97 ssize_t Write(const int fd, const std::size_t len); 98 std::size_t Get(char* dest, const std::size_t len); 99 int Put(const char* str, const std::size_t len); 100 int Put(const std::string& str); 101 102 private: FreeSize()103 inline std::size_t FreeSize() const 104 { 105 int res {0}; 106 res = head_ - tail_; 107 if (res <= 0) { 108 res += bufSize_; 109 } 110 return static_cast<std::size_t>(res); 111 } 112 inline std::size_t DataSize(int noLock = 1) const 113 { 114 int res {0}; 115 res = tail_ - head_; 116 if (res < 0) { 117 res += bufSize_; 118 } 119 return static_cast<std::size_t>(res); 120 } 121 inline std::size_t Capacity(int noLock = 1) const 122 { 123 return bufSize_; 124 } 125 126 int Resize(); 127 char* Allocate(std::size_t bufSize); 128 129 enum BufferSize:std::size_t { 130 DEFAULT_SIZE = (1 << 8), 131 }; 132 char *buffer_ {nullptr}; 133 std::size_t bufSize_ {DEFAULT_SIZE}; 134 const std::size_t alignShift_ {B_ALIGN_SHIFT}; 135 /* head_ = tail_ mean empty, the buffer can never be full */ 136 std::size_t head_ {0}; // first readable byte 137 std::size_t tail_ {0}; // first writebale byte 138 std::mutex mtx_; 139 }; 140 #endif