/src/common/containers/BinaryQueue.cpp

https://gitlab.com/github-cloud-corporation/cynara · C++ · 251 lines · 159 code · 44 blank · 48 comment · 21 complexity · b5518d25f1b47d63183b4fb05217f75f MD5 · raw file

  1. /*
  2. * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * @file src/common/containers/BinaryQueue.cpp
  18. * @author Przemyslaw Dobrowolski <p.dobrowolsk@samsung.com>
  19. * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
  20. * @version 1.0
  21. * @brief This file is the implementation file of binary queue
  22. */
  23. #include <algorithm>
  24. #include <cstring>
  25. #include <malloc.h>
  26. #include <new>
  27. #include <stddef.h>
  28. #include <attributes/attributes.h>
  29. #include <exceptions/NullPointerException.h>
  30. #include <exceptions/OutOfDataException.h>
  31. #include "BinaryQueue.h"
  32. namespace Cynara {
  33. BinaryQueue::BinaryQueue() : m_size(0) {
  34. }
  35. BinaryQueue::BinaryQueue(const BinaryQueue &other) : m_size(0) {
  36. appendCopyFrom(other);
  37. }
  38. BinaryQueue::~BinaryQueue() {
  39. // Remove all remaining buckets
  40. clear();
  41. }
  42. const BinaryQueue &BinaryQueue::operator=(const BinaryQueue &other) {
  43. if (this != &other) {
  44. clear();
  45. appendCopyFrom(other);
  46. }
  47. return *this;
  48. }
  49. void BinaryQueue::appendCopyFrom(const BinaryQueue &other) {
  50. // To speed things up, always copy as one bucket
  51. void *bufferCopy = malloc(other.m_size);
  52. if (bufferCopy == nullptr) {
  53. throw std::bad_alloc();
  54. }
  55. try {
  56. other.flatten(bufferCopy, other.m_size);
  57. appendUnmanaged(bufferCopy, other.m_size, &bufferDeleterFree, nullptr);
  58. } catch (const std::bad_alloc &) {
  59. // Free allocated memory
  60. free(bufferCopy);
  61. throw;
  62. }
  63. }
  64. void BinaryQueue::appendMoveFrom(BinaryQueue &other) {
  65. // Copy all buckets
  66. std::copy(other.m_buckets.begin(),
  67. other.m_buckets.end(), std::back_inserter(m_buckets));
  68. m_size += other.m_size;
  69. // Clear other, but do not free memory
  70. other.m_buckets.clear();
  71. other.m_size = 0;
  72. }
  73. void BinaryQueue::appendCopyTo(BinaryQueue &other) const {
  74. other.appendCopyFrom(*this);
  75. }
  76. void BinaryQueue::appendMoveTo(BinaryQueue &other) {
  77. other.appendMoveFrom(*this);
  78. }
  79. void BinaryQueue::clear() {
  80. std::for_each(m_buckets.begin(), m_buckets.end(), &deleteBucket);
  81. m_buckets.clear();
  82. m_size = 0;
  83. }
  84. void BinaryQueue::appendCopy(const void* buffer, size_t bufferSize) {
  85. // Create data copy with malloc/free
  86. void *bufferCopy = malloc(bufferSize);
  87. // Check if allocation succeded
  88. if (bufferCopy == nullptr) {
  89. throw std::bad_alloc();
  90. }
  91. // Copy user data
  92. memcpy(bufferCopy, buffer, bufferSize);
  93. try {
  94. // Try to append new bucket
  95. appendUnmanaged(bufferCopy, bufferSize, &bufferDeleterFree, nullptr);
  96. } catch (const std::bad_alloc &) {
  97. // Free allocated memory
  98. free(bufferCopy);
  99. throw;
  100. }
  101. }
  102. void BinaryQueue::appendUnmanaged(const void* buffer,
  103. size_t bufferSize,
  104. BufferDeleter deleter,
  105. void* userParam) {
  106. // Do not attach empty buckets
  107. if (bufferSize == 0) {
  108. deleter(buffer, bufferSize, userParam);
  109. return;
  110. }
  111. // Just add new bucket with selected deleter
  112. Bucket *bucket = new Bucket(buffer, bufferSize, deleter, userParam);
  113. try {
  114. m_buckets.push_back(bucket);
  115. } catch (const std::bad_alloc &) {
  116. delete bucket;
  117. throw;
  118. }
  119. // Increase total queue size
  120. m_size += bufferSize;
  121. }
  122. size_t BinaryQueue::size() const {
  123. return m_size;
  124. }
  125. bool BinaryQueue::empty() const {
  126. return m_size == 0;
  127. }
  128. void BinaryQueue::consume(size_t size) {
  129. // Check parameters
  130. if (size > m_size) {
  131. throw OutOfDataException(m_size, size);
  132. }
  133. size_t bytesLeft = size;
  134. // Consume data and/or remove buckets
  135. while (bytesLeft > 0) {
  136. // Get consume size
  137. size_t count = std::min(bytesLeft, m_buckets.front()->left);
  138. m_buckets.front()->ptr =
  139. static_cast<const char *>(m_buckets.front()->ptr) + count;
  140. m_buckets.front()->left -= count;
  141. bytesLeft -= count;
  142. m_size -= count;
  143. if (m_buckets.front()->left == 0) {
  144. deleteBucket(m_buckets.front());
  145. m_buckets.pop_front();
  146. }
  147. }
  148. }
  149. void BinaryQueue::flatten(void *buffer, size_t bufferSize) const {
  150. // Check parameters
  151. if (bufferSize == 0) {
  152. return;
  153. }
  154. if (bufferSize > m_size) {
  155. throw OutOfDataException(m_size, bufferSize);
  156. }
  157. size_t bytesLeft = bufferSize;
  158. void *ptr = buffer;
  159. BucketList::const_iterator bucketIterator = m_buckets.begin();
  160. // Flatten data
  161. while (bytesLeft > 0) {
  162. // Get consume size
  163. // todo a check is needed if bucketIterator doesn't point to m_buckets.end()
  164. size_t count = std::min(bytesLeft, (*bucketIterator)->left);
  165. // Copy data to user pointer
  166. memcpy(ptr, (*bucketIterator)->ptr, count);
  167. // Update flattened bytes count
  168. bytesLeft -= count;
  169. ptr = static_cast<char *>(ptr) + count;
  170. // Take next bucket
  171. ++bucketIterator;
  172. }
  173. }
  174. void BinaryQueue::flattenConsume(void *buffer, size_t bufferSize) {
  175. // FIXME: Optimize
  176. flatten(buffer, bufferSize);
  177. consume(bufferSize);
  178. }
  179. void BinaryQueue::deleteBucket(BinaryQueue::Bucket *bucket) {
  180. delete bucket;
  181. }
  182. void BinaryQueue::bufferDeleterFree(const void* data,
  183. size_t dataSize UNUSED,
  184. void* userParam UNUSED) {
  185. // Default free deleter
  186. free(const_cast<void *>(data));
  187. }
  188. BinaryQueue::Bucket::Bucket(const void* data,
  189. size_t dataSize,
  190. BufferDeleter dataDeleter,
  191. void* userParam) :
  192. buffer(data),
  193. ptr(data),
  194. size(dataSize),
  195. left(dataSize),
  196. deleter(dataDeleter),
  197. param(userParam) {
  198. if(data == nullptr)
  199. throw NullPointerException("data");
  200. if(dataDeleter == nullptr)
  201. throw NullPointerException("dataDeleter");
  202. }
  203. BinaryQueue::Bucket::~Bucket() {
  204. // Invoke deleter on bucket data
  205. deleter(buffer, size, param);
  206. }
  207. } // namespace Cynara