97f19e1064c1574882e03301926b8cc211cfddd9
[platform/core/security/key-manager.git] / src / manager / dpl / core / src / binary_queue.cpp
1 /*
2  * Copyright (c) 2011-2020 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        binary_queue.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of binary queue
21  */
22 #include <stddef.h>
23 #include <dpl/binary_queue.h>
24 #include <cassert>
25 #include <algorithm>
26 #include <functional>
27 #include <malloc.h>
28 #include <cstring>
29 #include <new>
30
31 namespace CKM {
32 BinaryQueue::BinaryQueue() :
33         m_size(0)
34 {}
35
36 BinaryQueue::BinaryQueue(const BinaryQueue &other) :
37         m_size(0)
38 {
39         AppendCopyFrom(other);
40 }
41
42 BinaryQueue::~BinaryQueue()
43 {
44         // Remove all remainig buckets
45         Clear();
46 }
47
48 const BinaryQueue &BinaryQueue::operator=(const BinaryQueue &other)
49 {
50         if (this != &other) {
51                 Clear();
52                 AppendCopyFrom(other);
53         }
54
55         return *this;
56 }
57
58 void BinaryQueue::AppendCopyFrom(const BinaryQueue &other)
59 {
60         // To speed things up, always copy as one bucket
61         void *bufferCopy = malloc(other.m_size);
62
63         if (bufferCopy == NULL)
64                 throw std::bad_alloc();
65
66         try {
67                 other.Flatten(bufferCopy, other.m_size);
68                 AppendUnmanaged(bufferCopy, other.m_size, &BufferDeleterFree, NULL);
69         } catch (const std::bad_alloc &) {
70                 // Free allocated memory
71                 free(bufferCopy);
72                 throw;
73         }
74 }
75
76 void BinaryQueue::AppendMoveFrom(BinaryQueue &other)
77 {
78         // Copy all buckets
79         std::copy(other.m_buckets.begin(),
80                           other.m_buckets.end(), std::back_inserter(m_buckets));
81         m_size += other.m_size;
82
83         // Clear other, but do not free memory
84         other.m_buckets.clear();
85         other.m_size = 0;
86 }
87
88 void BinaryQueue::AppendCopyTo(BinaryQueue &other) const
89 {
90         other.AppendCopyFrom(*this);
91 }
92
93 void BinaryQueue::AppendMoveTo(BinaryQueue &other)
94 {
95         other.AppendMoveFrom(*this);
96 }
97
98 void BinaryQueue::Clear()
99 {
100         std::for_each(m_buckets.begin(), m_buckets.end(), &DeleteBucket);
101         m_buckets.clear();
102         m_size = 0;
103 }
104
105 void BinaryQueue::AppendCopy(const void *buffer, size_t bufferSize)
106 {
107         // Create data copy with malloc/free
108         void *bufferCopy = malloc(bufferSize);
109
110         // Check if allocation succeded
111         if (bufferCopy == NULL)
112                 throw std::bad_alloc();
113
114         // Copy user data
115         memcpy(bufferCopy, buffer, bufferSize);
116
117         try {
118                 // Try to append new bucket
119                 AppendUnmanaged(bufferCopy, bufferSize, &BufferDeleterFree, NULL);
120         } catch (const std::bad_alloc &) {
121                 // Free allocated memory
122                 free(bufferCopy);
123                 throw;
124         }
125 }
126
127 void BinaryQueue::AppendUnmanaged(const void *buffer,
128                                                                   size_t bufferSize,
129                                                                   BufferDeleter deleter,
130                                                                   void *userParam)
131 {
132         // Do not attach empty buckets
133         if (bufferSize == 0) {
134                 deleter(buffer, bufferSize, userParam);
135                 return;
136         }
137
138         // Just add new bucket with selected deleter
139         Bucket *bucket = new Bucket(buffer, bufferSize, deleter, userParam);
140
141         try {
142                 m_buckets.push_back(bucket);
143         } catch (const std::bad_alloc &) {
144                 delete bucket;
145                 throw;
146         }
147
148         // Increase total queue size
149         m_size += bufferSize;
150 }
151
152 size_t BinaryQueue::Size() const
153 {
154         return m_size;
155 }
156
157 bool BinaryQueue::Empty() const
158 {
159         return m_size == 0;
160 }
161
162 void BinaryQueue::Consume(size_t size)
163 {
164         // Check parameters
165         if (size > m_size)
166                 Throw(Exception::OutOfData);
167
168         size_t bytesLeft = size;
169
170         // Consume data and/or remove buckets
171         while (bytesLeft > 0) {
172                 // Get consume size
173                 size_t count = std::min(bytesLeft, m_buckets.front()->left);
174
175                 m_buckets.front()->ptr =
176                         static_cast<const char *>(m_buckets.front()->ptr) + count;
177                 m_buckets.front()->left -= count;
178                 bytesLeft -= count;
179                 m_size -= count;
180
181                 if (m_buckets.front()->left == 0) {
182                         DeleteBucket(m_buckets.front());
183                         m_buckets.pop_front();
184                 }
185         }
186 }
187
188 void BinaryQueue::Flatten(void *buffer, size_t bufferSize) const
189 {
190         // Check parameters
191         if (bufferSize == 0)
192                 return;
193
194         if (bufferSize > m_size)
195                 Throw(Exception::OutOfData);
196
197         size_t bytesLeft = bufferSize;
198         void *ptr = buffer;
199         BucketList::const_iterator bucketIterator = m_buckets.begin();
200         assert(m_buckets.end() != bucketIterator);
201
202         // Flatten data
203         while (bytesLeft > 0) {
204                 // Get consume size
205                 size_t count = std::min(bytesLeft, (*bucketIterator)->left);
206
207                 // Copy data to user pointer
208                 memcpy(ptr, (*bucketIterator)->ptr, count);
209
210                 // Update flattened bytes count
211                 bytesLeft -= count;
212                 ptr = static_cast<char *>(ptr) + count;
213
214                 // Take next bucket
215                 ++bucketIterator;
216         }
217 }
218
219 void BinaryQueue::FlattenConsume(void *buffer, size_t bufferSize)
220 {
221         // FIXME: Optimize
222         Flatten(buffer, bufferSize);
223         Consume(bufferSize);
224 }
225
226 void BinaryQueue::DeleteBucket(BinaryQueue::Bucket *bucket)
227 {
228         delete bucket;
229 }
230
231 void BinaryQueue::BufferDeleterFree(const void *data,
232                                                                         size_t dataSize,
233                                                                         void *userParam)
234 {
235         (void)dataSize;
236         (void)userParam;
237
238         // Default free deleter
239         free(const_cast<void *>(data));
240 }
241
242 BinaryQueue::Bucket::Bucket(const void *data,
243                                                         size_t dataSize,
244                                                         BufferDeleter dataDeleter,
245                                                         void *userParam) :
246         buffer(data),
247         ptr(data),
248         size(dataSize),
249         left(dataSize),
250         deleter(dataDeleter),
251         param(userParam)
252 {
253         assert(data != NULL);
254         assert(deleter != NULL);
255 }
256
257 BinaryQueue::Bucket::~Bucket()
258 {
259         // Invoke deleter on bucket data
260         deleter(buffer, size, param);
261 }
262
263 BinaryQueue::BucketVisitor::~BucketVisitor()
264 {
265 }
266
267 BinaryQueue::BucketVisitorCall::BucketVisitorCall(BucketVisitor *visitor) :
268         m_visitor(visitor)
269 {
270 }
271
272 BinaryQueue::BucketVisitorCall::~BucketVisitorCall()
273 {
274 }
275
276 void BinaryQueue::BucketVisitorCall::operator()(Bucket *bucket) const
277 {
278         m_visitor->OnVisitBucket(bucket->ptr, bucket->left);
279 }
280
281 void BinaryQueue::VisitBuckets(BucketVisitor *visitor) const
282 {
283         assert(visitor != NULL);
284
285         // Visit all buckets
286         std::for_each(m_buckets.begin(), m_buckets.end(), BucketVisitorCall(visitor));
287 }
288
289 BinaryQueueUniquePtr BinaryQueue::Read(size_t size)
290 {
291         // Simulate input stream
292         size_t available = std::min(size, m_size);
293
294         std::unique_ptr<void, std::function<void(void *)>>
295                         bufferCopy(malloc(available), free);
296
297         if (!bufferCopy.get())
298                 throw std::bad_alloc();
299
300         BinaryQueueUniquePtr result(new BinaryQueue());
301
302         Flatten(bufferCopy.get(), available);
303         result->AppendUnmanaged(
304                 bufferCopy.release(), available, &BufferDeleterFree, NULL);
305         Consume(available);
306
307         return result;
308 }
309
310 size_t BinaryQueue::Write(const BinaryQueue &buffer, size_t bufferSize)
311 {
312         // Simulate output stream
313         AppendCopyFrom(buffer);
314         return bufferSize;
315 }
316 } // namespace CKM