Merge pull request #1551 from DOCGroup/plm_jira_333
[ACE_TAO.git] / TAO / tao / Unbounded_Octet_Sequence_T.h
blobc3ec3ec5bbd63404920e166b95b1c1063e2b7094
1 #ifndef guard_unbounded_octet_sequence_hpp
2 #define guard_unbounded_octet_sequence_hpp
3 /**
4 * @file
6 * @brief Implement octet sequences
8 * @author Johnny Willemsen
9 */
10 #include "tao/orbconf.h"
12 #include "tao/Unbounded_Value_Sequence_T.h"
13 #include "ace/OS_NS_string.h"
15 #if (TAO_NO_COPY_OCTET_SEQUENCES == 1)
17 #include /**/ "tao/TAO_Export.h"
18 #include "tao/Unbounded_Value_Allocation_Traits_T.h"
19 #include "tao/Value_Traits_T.h"
20 #include "tao/Range_Checking_T.h"
22 #include "tao/Basic_Types.h"
23 #include "ace/Message_Block.h"
24 #include "ace/OS_Memory.h"
25 #include "ace/checked_iterator.h"
27 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
29 namespace TAO
31 template<>
32 class TAO_Export unbounded_value_sequence<CORBA::Octet>
34 public:
35 typedef CORBA::Octet value_type;
36 typedef CORBA::Octet element_type;
37 typedef CORBA::Octet const const_value_type;
38 typedef value_type & subscript_type;
39 typedef value_type const & const_subscript_type;
40 typedef ::CORBA::ULong size_type;
42 typedef details::unbounded_value_allocation_traits<value_type,true> allocation_traits;
43 typedef details::value_traits<value_type,true> element_traits;
44 typedef details::generic_sequence<value_type, allocation_traits, element_traits> implementation_type;
45 typedef details::range_checking<value_type,true> range;
47 inline unbounded_value_sequence<CORBA::Octet>()
48 : maximum_ (allocation_traits::default_maximum())
49 , length_ (0)
50 , buffer_ (allocation_traits::default_buffer_allocation())
51 , release_ (buffer_ != 0)
52 , mb_ (0)
54 inline explicit unbounded_value_sequence<CORBA::Octet>(CORBA::ULong maximum)
55 : maximum_(maximum)
56 , length_(0)
57 , buffer_(allocbuf(maximum_))
58 , release_(true)
59 , mb_ (0)
61 inline unbounded_value_sequence<CORBA::Octet>(
62 CORBA::ULong maximum,
63 CORBA::ULong length,
64 value_type * data,
65 CORBA::Boolean release = false)
66 : maximum_ (maximum),
67 length_ (length),
68 buffer_ (data),
69 release_ (release),
70 mb_ (0)
72 inline ~unbounded_value_sequence<CORBA::Octet>() {
73 if (mb_)
74 ACE_Message_Block::release (mb_);
75 if (release_)
76 freebuf(buffer_);
78 /// Create a sequence of octets from a single message block (i.e. it
79 /// ignores any chaining in the message block).
80 inline unbounded_value_sequence<CORBA::Octet> (CORBA::ULong length,
81 const ACE_Message_Block* mb)
82 : maximum_ (length)
83 , length_ (length)
84 , buffer_ (reinterpret_cast <CORBA::Octet *>(mb->rd_ptr ()))
85 , release_ (false)
86 , mb_(0) {
87 // Get the message block flags.
88 ACE_Message_Block::Message_Flags const flg = mb->self_flags ();
90 // If the DONT_DELETE flag is disabled just a duplicate would
91 // help. If the DONT_DELETE flag is enabled a deep copy is needed as
92 // the contents would be on stack. Just incrementing the ref count
93 // on the stack based data block would only crash the program when
94 // the stack unwinds
95 if (ACE_BIT_DISABLED (flg,
96 ACE_Message_Block::DONT_DELETE))
98 this->mb_ = ACE_Message_Block::duplicate (mb);
100 else
102 // As we are in CORBA mode, all the data blocks would be aligned
103 // on an 8 byte boundary
104 ACE_Message_Block msgb (*mb, ACE_CDR::MAX_ALIGNMENT);
106 // Get the base pointer of the incoming message block
107 char *const start = ACE_ptr_align_binary (mb->base (),
108 ACE_CDR::MAX_ALIGNMENT);
110 // Get the read and write displacements in the incoming stream
111 size_t const rd_pos = mb->rd_ptr () - start;
112 size_t const wr_pos = mb->wr_ptr () - start;
114 this->mb_ = ACE_Message_Block::duplicate (&msgb);
116 this->mb_->rd_ptr (rd_pos);
117 this->mb_->wr_ptr (wr_pos);
120 inline CORBA::ULong maximum() const {
121 return maximum_;
123 inline CORBA::Boolean release() const {
124 return release_;
126 inline CORBA::ULong length() const {
127 return length_;
129 inline void length(CORBA::ULong length) {
130 if (length <= maximum_)
132 if (this->mb_ == 0)
134 length_ = length;
136 else
138 unbounded_value_sequence<CORBA::Octet> tmp(length);
139 tmp.length_ = length;
140 element_traits::copy_range(
141 buffer_,
142 buffer_ + length,
143 ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
144 swap(tmp);
146 return;
149 unbounded_value_sequence<CORBA::Octet> tmp(length);
150 tmp.length_ = length;
151 element_traits::copy_range(
152 buffer_,
153 buffer_ + length_,
154 ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
155 swap(tmp);
157 inline value_type const & operator[](CORBA::ULong i) const {
158 range::check(i, length_, maximum_, "operator[]() const");
159 return buffer_[i];
161 inline value_type & operator[](CORBA::ULong i) {
162 range::check(i, length_, maximum_, "operator[]() non-const");
163 return buffer_[i];
165 inline void replace(
166 CORBA::ULong maximum,
167 CORBA::ULong length,
168 value_type * data,
169 CORBA::Boolean release = false) {
170 unbounded_value_sequence<CORBA::Octet> tmp(maximum, length, data, release);
171 swap(tmp);
173 inline value_type const * get_buffer() const {
174 if (buffer_ == 0)
176 buffer_ = allocbuf(maximum_);
177 release_ = true;
179 return buffer_;
181 inline value_type * get_buffer(CORBA::Boolean orphan = false) {
182 if (orphan && !release_)
184 return 0;
186 if (buffer_ == 0)
188 buffer_ = allocbuf(maximum_);
189 if (!orphan)
191 release_ = true;
194 if (!orphan)
196 return buffer_;
199 unbounded_value_sequence<CORBA::Octet> tmp;
200 swap(tmp);
201 tmp.release_ = false;
203 return tmp.buffer_;
206 // moved inside the class to resolve namespace lookup issues.
207 // This is a replacement for the commented block below.
208 inline bool operator== (const unbounded_value_sequence<CORBA::Octet> & rhs) const {
209 unbounded_value_sequence<CORBA::Octet> const & lhs = *this;
210 CORBA::ULong const len = lhs.length();
212 // We use the subscript operator instead of get_buffer() to avoid a
213 // potential buffer allocation.
214 return
215 (len == rhs.length()
216 && (len == 0
217 ? true
218 : ACE_OS::memcmp(&lhs[0], &rhs[0], len) == 0));
221 inline bool operator!= (const unbounded_value_sequence<CORBA::Octet> & rhs) const
223 return !this->operator==(rhs);
226 inline void swap(unbounded_value_sequence & rhs) throw() {
227 std::swap (mb_, rhs.mb_);
228 std::swap (maximum_, rhs.maximum_);
229 std::swap (length_, rhs.length_);
230 std::swap (buffer_, rhs.buffer_);
231 std::swap (release_, rhs.release_);
233 static value_type * allocbuf(CORBA::ULong maximum) {
234 return allocation_traits::allocbuf(maximum);
236 static void freebuf(value_type * buffer) {
237 allocation_traits::freebuf(buffer);
240 /// Returns the underlying message block, the caller must *not*
241 /// release the copy.
242 inline ACE_Message_Block* mb (void) const {
243 return mb_;
246 /// Replaces the current buffer with @a mb, using only @a length bytes.
247 /// It takes a duplicate of <mb> so the user still owns it.
248 inline void replace (CORBA::ULong length, const ACE_Message_Block* mb) {
249 unbounded_value_sequence<CORBA::Octet> s (length, mb);
250 swap (s);
253 unbounded_value_sequence<CORBA::Octet> (
254 const unbounded_value_sequence<CORBA::Octet> &rhs)
255 : maximum_ (0)
256 , length_ (0)
257 , buffer_(0)
258 , release_(false)
259 , mb_ (0)
261 if (rhs.maximum_ == 0 || rhs.buffer_ == 0)
263 maximum_ = rhs.maximum_;
264 length_ = rhs.length_;
265 return;
267 unbounded_value_sequence<CORBA::Octet> tmp(rhs.maximum_);
268 tmp.length_ = rhs.length_;
269 if (rhs.mb_ == 0)
271 ACE_OS::memcpy (tmp.buffer_,
272 rhs.buffer_,
273 rhs.length_);
275 else
277 size_t offset = 0;
278 for (const ACE_Message_Block *i = rhs.mb_; i != 0; i = i->cont ())
280 ACE_OS::memcpy (tmp.buffer_ + offset,
281 i->rd_ptr (),
282 i->length ());
284 offset += i->length ();
287 swap(tmp);
290 unbounded_value_sequence<CORBA::Octet> &
291 operator= (const unbounded_value_sequence<CORBA::Octet> & rhs)
293 unbounded_value_sequence<CORBA::Octet> tmp(rhs);
294 swap(tmp);
295 return * this;
298 private:
299 /// The maximum number of elements the buffer can contain.
300 CORBA::ULong maximum_;
302 /// The current number of elements in the buffer.
303 CORBA::ULong length_;
305 /// The buffer with all the elements, casting must be done in derived
306 /// classes.
307 mutable value_type * buffer_;
309 /// If true then the sequence should release the buffer when it is
310 /// destroyed.
311 mutable CORBA::Boolean release_;
312 ACE_Message_Block* mb_;
315 } // namespace TAO
317 TAO_END_VERSIONED_NAMESPACE_DECL
319 #endif /* TAO_NO_COPY_OCTET_SEQUENCES == 1 */
321 #if (TAO_NO_COPY_OCTET_SEQUENCES == 0)
323 // This doesn't work always for unexplained reason. At least
324 // PortableServer::Active_Object_Map.cpp fails to compile with some compilers.
325 // But I'm keeping this in for the moment so that it may be
326 // resurrected if need be
327 inline
328 bool
329 operator== (const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & lhs,
330 const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & rhs)
332 ::CORBA::ULong const rlen = rhs.length ();
334 if (rlen != lhs.length ())
336 return false;
339 const CORBA::Octet * rhs_buff = rhs.get_buffer ();
340 const CORBA::Octet * lhs_buff = lhs.get_buffer ();
341 const bool result = (ACE_OS::memcmp (lhs_buff, rhs_buff, rlen) == 0);
343 return result;
346 inline
347 bool
348 operator!= (const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & lhs,
349 const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & rhs)
351 return !(lhs == rhs);
353 #endif /* TAO_NO_COPY_OCTET_SEQUENCES==0 */
355 #endif // guard_unbounded_octet_sequence_hpp