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