Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-core.git] / dali / internal / common / message-buffer.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
18 // CLASS HEADER
19 #include <dali/internal/common/message-buffer.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <cstdlib>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/debug.h>
27
28 namespace // unnamed namespace
29 {
30
31 // Increase capacity by 1.5 when buffer limit reached
32 const unsigned int INCREMENT_NUMERATOR   = 3u;
33 const unsigned int INCREMENT_DENOMINATOR = 2u;
34
35 const unsigned int MESSAGE_SIZE_FIELD = 1u; // Size required to mark the message size
36 const unsigned int MESSAGE_END_FIELD  = 1u; // Size required to mark the end of messages
37
38 const unsigned int MESSAGE_SIZE_PLUS_END_FIELD = MESSAGE_SIZE_FIELD + MESSAGE_END_FIELD;
39
40 const unsigned int MAX_DIVISION_BY_WORD_REMAINDER = sizeof(Dali::Internal::MessageBuffer::WordType) - 1u; // For word alignment on ARM
41 const unsigned int WORD_SIZE = sizeof(Dali::Internal::MessageBuffer::WordType);
42
43 } // unnamed namespace
44
45 namespace Dali
46 {
47
48 namespace Internal
49 {
50
51 MessageBuffer::MessageBuffer( std::size_t initialCapacity )
52 : mInitialCapacity( initialCapacity / WORD_SIZE ),
53   mData( NULL ),
54   mNextSlot( NULL ),
55   mCapacity( 0 ),
56   mSize( 0 )
57 {
58 }
59
60 MessageBuffer::~MessageBuffer()
61 {
62   free( mData );
63 }
64
65 unsigned int* MessageBuffer::ReserveMessageSlot( std::size_t size )
66 {
67   DALI_ASSERT_DEBUG( 0 != size );
68
69   // Number of aligned words required to handle a message of size in bytes
70   std::size_t requestedSize = (size + MAX_DIVISION_BY_WORD_REMAINDER) / WORD_SIZE;
71   std::size_t requiredSize = requestedSize + MESSAGE_SIZE_PLUS_END_FIELD;
72
73   // Keep doubling the additional capacity until we have enough
74   std::size_t nextCapacity = mCapacity ? mCapacity : mInitialCapacity;
75
76   if ( (nextCapacity - mSize) < requiredSize )
77   {
78     nextCapacity = nextCapacity * INCREMENT_NUMERATOR / INCREMENT_DENOMINATOR;
79
80     // Something has gone badly wrong if requiredSize is this big
81     DALI_ASSERT_DEBUG( (nextCapacity - mSize) > requiredSize );
82   }
83
84   if ( nextCapacity > mCapacity )
85   {
86     IncreaseCapacity( nextCapacity );
87   }
88
89   // Now reserve the slot
90   WordType* slot = mNextSlot;
91
92   *slot++ = requestedSize; // Object size marker is stored in first word
93
94   mSize += requestedSize + MESSAGE_SIZE_FIELD;
95   mNextSlot = mData + mSize;
96
97   // End marker
98   *mNextSlot = 0;
99
100   // @todo Remove cast & change all messages to use WordType instead
101   return reinterpret_cast<unsigned int*>(slot);
102 }
103
104 std::size_t MessageBuffer::GetCapacity() const
105 {
106   return mCapacity * WORD_SIZE;
107 }
108
109 MessageBuffer::Iterator MessageBuffer::Begin() const
110 {
111   if ( 0 != mSize )
112   {
113     return Iterator( mData );
114   }
115
116   return Iterator( NULL );
117 }
118
119 void MessageBuffer::Reset()
120 {
121   // All messages have been processed, reset the buffer
122   mSize = 0;
123   mNextSlot = mData;
124 }
125
126 void MessageBuffer::IncreaseCapacity( std::size_t newCapacity )
127 {
128   DALI_ASSERT_DEBUG( newCapacity > mCapacity );
129
130   if ( mData )
131   {
132     // Often this avoids the need to copy memory
133
134     WordType* oldData = mData;
135     mData = reinterpret_cast<WordType*>( realloc( mData, newCapacity * WORD_SIZE ) );
136
137     // if realloc fails the old data is still valid
138     if( !mData )
139     {
140       // TODO: Process message queue to free up some data?
141       free(oldData);
142       DALI_ASSERT_DEBUG( false && "Realloc failed we're out of memory!" );
143     }
144   }
145   else
146   {
147     mData = reinterpret_cast<WordType*>( malloc( newCapacity * WORD_SIZE ) );
148   }
149   DALI_ASSERT_ALWAYS( NULL != mData );
150
151   mCapacity = newCapacity;
152   mNextSlot = mData + mSize;
153 }
154
155 MessageBuffer::Iterator::Iterator(WordType* current)
156 : mCurrent(current),
157   mMessageSize(0)
158 {
159   if( NULL != mCurrent )
160   {
161     // The first word is the size of the following object
162     mMessageSize = *mCurrent++;
163   }
164 }
165
166 MessageBuffer::Iterator::Iterator(const Iterator& copy)
167 : mCurrent( copy.mCurrent ),
168   mMessageSize( copy.mMessageSize )
169 {
170 }
171
172 } // namespace Internal
173
174 } // namespace Dali