Unbounded_Octet_Sequence_T.h

Go to the documentation of this file.
00001 #ifndef guard_unbounded_octet_sequence_hpp
00002 #define guard_unbounded_octet_sequence_hpp
00003 /**
00004  * @file
00005  *
00006  * @brief Implement octet sequences
00007  *
00008  * $Id: Unbounded_Octet_Sequence_T.h 78863 2007-07-13 00:21:36Z ossama $
00009  *
00010  * @author Johnny Willemsen
00011  */
00012 #include "tao/orbconf.h"
00013 
00014 #include "tao/Unbounded_Value_Sequence_T.h"
00015 #include "ace/OS_NS_string.h"
00016 
00017 #if (TAO_NO_COPY_OCTET_SEQUENCES == 1)
00018 
00019 #include /**/ "tao/TAO_Export.h"
00020 #include "tao/Unbounded_Value_Allocation_Traits_T.h"
00021 #include "tao/Value_Traits_T.h"
00022 #include "tao/Range_Checking_T.h"
00023 
00024 #include "tao/Basic_Types.h"
00025 #include "ace/Message_Block.h"
00026 #include "ace/OS_Memory.h"
00027 #include "ace/checked_iterator.h"
00028 
00029 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00030 
00031 namespace TAO
00032 {
00033 template<>
00034 class TAO_Export unbounded_value_sequence<CORBA::Octet>
00035 {
00036 public:
00037   typedef CORBA::Octet value_type;
00038   typedef CORBA::Octet element_type;
00039   typedef CORBA::Octet const const_value_type;
00040   typedef value_type & subscript_type;
00041   typedef value_type const & const_subscript_type;
00042 
00043   typedef details::unbounded_value_allocation_traits<value_type,true> allocation_traits;
00044   typedef details::value_traits<value_type,true> element_traits;
00045   typedef details::generic_sequence<value_type, allocation_traits, element_traits> implementation_type;
00046   typedef details::range_checking<value_type,true> range;
00047 
00048   inline unbounded_value_sequence<CORBA::Octet>()
00049     : maximum_ (allocation_traits::default_maximum())
00050     , length_ (0)
00051     , buffer_ (allocation_traits::default_buffer_allocation())
00052     , release_ (true)
00053     , mb_ (0)
00054   {}
00055   inline explicit unbounded_value_sequence<CORBA::Octet>(CORBA::ULong maximum)
00056     : maximum_(maximum)
00057     , length_(0)
00058     , buffer_(allocbuf(maximum_))
00059     , release_(true)
00060     , mb_ (0)
00061   {}
00062   inline unbounded_value_sequence<CORBA::Octet>(
00063       CORBA::ULong maximum,
00064       CORBA::ULong length,
00065       value_type * data,
00066       CORBA::Boolean release = false)
00067     : maximum_ (maximum),
00068       length_ (length),
00069       buffer_ (data),
00070       release_ (release),
00071       mb_ (0)
00072   {}
00073   inline ~unbounded_value_sequence<CORBA::Octet>() {
00074     if (mb_)
00075       ACE_Message_Block::release (mb_);
00076     if (release_)
00077       freebuf(buffer_);
00078   }
00079   /// Create a sequence of octets from a single message block (i.e. it
00080   /// ignores any chaining in the meesage block).
00081   inline unbounded_value_sequence<CORBA::Octet> (CORBA::ULong length,
00082                                                  const ACE_Message_Block* mb)
00083     : maximum_ (length)
00084     , length_ (length)
00085     , buffer_ (reinterpret_cast <CORBA::Octet *>(mb->rd_ptr ()))
00086     , release_ (false)
00087     , mb_(0) {
00088     // Get the message block flags.
00089     ACE_Message_Block::Message_Flags const flg = mb->self_flags ();
00090 
00091     // If the DONT_DELETE flag is disabled just a duplicate would
00092     // help. If the DONT_DELETE flag is enabled a deep copy is needed as
00093     // the contents would be on stack. Just incrementing the ref count
00094     // on the stack based data block would only crash the program when
00095     // the stack unwinds
00096     if (ACE_BIT_DISABLED (flg,
00097                           ACE_Message_Block::DONT_DELETE))
00098       {
00099         this->mb_ = ACE_Message_Block::duplicate (mb);
00100       }
00101     else
00102       {
00103         // As we are in CORBA mode, all the data blocks would be aligned
00104         // on an 8 byte boundary
00105         ACE_Message_Block msgb (*mb,
00106                                 ACE_CDR::MAX_ALIGNMENT);
00107 
00108         // Get the base pointer of the incoming message block
00109         char *start = ACE_ptr_align_binary (mb->base (),
00110                                             ACE_CDR::MAX_ALIGNMENT);
00111 
00112         // Get the read and write displacements in the incoming stream
00113         size_t const rd_pos = mb->rd_ptr () - start;
00114         size_t const wr_pos = mb->wr_ptr () - start;
00115 
00116         this->mb_ = ACE_Message_Block::duplicate (&msgb);
00117 
00118         this->mb_->rd_ptr (rd_pos);
00119         this->mb_->wr_ptr (wr_pos);
00120       }
00121   }
00122   inline CORBA::ULong maximum() const {
00123     return maximum_;
00124   }
00125   inline CORBA::Boolean release() const {
00126     return release_;
00127   }
00128   inline CORBA::ULong length() const {
00129     return length_;
00130   }
00131   inline void length(CORBA::ULong length) {
00132     if (length <= maximum_ || length <= length_)
00133       {
00134         if (this->mb_ == 0)
00135           {
00136             if (length_ < length)
00137             {
00138               // TODO This code does not provide the strong-exception
00139               //      guarantee, but it does provide the weak-exception
00140               //      guarantee.  The problem would appear when
00141               //      initialize_range() raises an exception after several
00142               //      elements have been modified.  One could argue that
00143               //      this problem is irrelevant, as the elements already
00144               //      modified are unreachable to conforming applications.
00145               element_traits::initialize_range(
00146                   buffer_ + length_, buffer_ + length);
00147             }
00148             length_ = length;
00149           }
00150         else
00151           {
00152             unbounded_value_sequence<CORBA::Octet> tmp(length);
00153             tmp.length_ = length;
00154             element_traits::copy_range(
00155               buffer_,
00156               buffer_ + length,
00157               ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
00158             swap(tmp);
00159           }
00160         return;
00161       }
00162 
00163     unbounded_value_sequence<CORBA::Octet> tmp(length);
00164     tmp.length_ = length;
00165     element_traits::copy_range(
00166       buffer_,
00167       buffer_ + length_,
00168       ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
00169     element_traits::initialize_range(
00170         tmp.buffer_ + length_, tmp.buffer_ + length);
00171     swap(tmp);
00172   }
00173   inline value_type const & operator[](CORBA::ULong i) const {
00174     range::check(i, length_, maximum_, "operator[]() const");
00175     return buffer_[i];
00176   }
00177   inline value_type & operator[](CORBA::ULong i) {
00178     range::check(i, length_, maximum_, "operator[]() non-const");
00179     return buffer_[i];
00180   }
00181   inline void replace(
00182       CORBA::ULong maximum,
00183       CORBA::ULong length,
00184       value_type * data,
00185       CORBA::Boolean release = false) {
00186     unbounded_value_sequence<CORBA::Octet> tmp(maximum, length, data, release);
00187     swap(tmp);
00188   }
00189   inline value_type const * get_buffer() const {
00190     if (buffer_ == 0)
00191       {
00192         buffer_ = allocbuf(maximum_);
00193       }
00194     return buffer_;
00195   }
00196   inline value_type * get_buffer(CORBA::Boolean orphan = false) {
00197     if (orphan && !release_)
00198     {
00199       return 0;
00200     }
00201     if (buffer_ == 0)
00202     {
00203       buffer_ = allocbuf(maximum_);
00204     }
00205     if (!orphan)
00206     {
00207       return buffer_;
00208     }
00209 
00210     unbounded_value_sequence<CORBA::Octet> tmp;
00211     swap(tmp);
00212     tmp.release_ = false;
00213 
00214     return tmp.buffer_;
00215   }
00216 
00217   // moved inside the class to resolve namespace lookup issues.
00218   // This is a replacement for the commented block below.
00219   inline bool operator== (const unbounded_value_sequence<CORBA::Octet> & rhs) const {
00220     unbounded_value_sequence<CORBA::Octet> const & lhs = *this;
00221     CORBA::ULong const len = lhs.length();
00222 
00223     // We use the subscript operator instead of get_buffer() to avoid a
00224     // potential buffer allocation.
00225     return
00226       (len == rhs.length()
00227        && (len == 0
00228            ? true
00229            : ACE_OS::memcmp(&lhs[0], &rhs[0], len) == 0));
00230   }
00231 
00232   inline bool operator!= (const unbounded_value_sequence<CORBA::Octet> & rhs) const
00233   {
00234     return !this->operator==(rhs);
00235   }
00236 
00237   inline void swap(unbounded_value_sequence & rhs) throw() {
00238     std::swap (mb_, rhs.mb_);
00239     std::swap (maximum_, rhs.maximum_);
00240     std::swap (length_, rhs.length_);
00241     std::swap (buffer_, rhs.buffer_);
00242     std::swap (release_, rhs.release_);
00243   }
00244   static value_type * allocbuf(CORBA::ULong maximum) {
00245     return allocation_traits::allocbuf(maximum);
00246   }
00247   static void freebuf(value_type * buffer) {
00248     allocation_traits::freebuf(buffer);
00249   }
00250 
00251   /// Returns the underlying message block, the caller must *not*
00252   /// release the copy.
00253   inline ACE_Message_Block* mb (void) const {
00254     return mb_;
00255   }
00256 
00257   /// Replaces the current buffer with <mb>, using only <length> bytes.
00258   /// It takes a duplicate of <mb> so the user still owns it.
00259   inline void replace (CORBA::ULong length, const ACE_Message_Block* mb) {
00260     unbounded_value_sequence<CORBA::Octet> s (length, mb);
00261     swap (s);
00262   }
00263 
00264   unbounded_value_sequence<CORBA::Octet> (
00265     const unbounded_value_sequence<CORBA::Octet> &rhs)
00266     : maximum_ (0)
00267     , length_ (0)
00268     , buffer_(0)
00269     , release_(false)
00270     , mb_ (0)
00271   {
00272     unbounded_value_sequence<CORBA::Octet> tmp(rhs.maximum_);
00273     tmp.length_ = rhs.length_;
00274     if (rhs.mb_ == 0)
00275       {
00276         ACE_OS::memcpy (tmp.buffer_,
00277                         rhs.buffer_,
00278                         rhs.length_);
00279       }
00280     else
00281       {
00282         size_t offset = 0;
00283         for (const ACE_Message_Block *i = rhs.mb_; i != 0; i = i->cont ())
00284           {
00285             ACE_OS::memcpy (tmp.buffer_ + offset,
00286                             i->rd_ptr (),
00287                             i->length ());
00288 
00289             offset += i->length ();
00290           }
00291       }
00292     swap(tmp);
00293   }
00294 
00295   unbounded_value_sequence<CORBA::Octet> &
00296   operator= (const unbounded_value_sequence<CORBA::Octet> & rhs)
00297   {
00298     unbounded_value_sequence<CORBA::Octet> tmp(rhs);
00299     swap(tmp);
00300     return * this;
00301   }
00302 
00303 private:
00304   /// The maximum number of elements the buffer can contain.
00305   CORBA::ULong maximum_;
00306 
00307   /// The current number of elements in the buffer.
00308   CORBA::ULong length_;
00309 
00310   /// The buffer with all the elements, casting must be done in derived
00311   /// classes.
00312   mutable value_type * buffer_;
00313 
00314   /// If true then the sequence should release the buffer when it is
00315   /// destroyed.
00316   CORBA::Boolean release_;
00317   ACE_Message_Block* mb_;
00318 };
00319 
00320 } // namespace TAO
00321 
00322 TAO_END_VERSIONED_NAMESPACE_DECL
00323 
00324 #endif /* TAO_NO_COPY_OCTET_SEQUENCES == 1 */
00325 
00326 #if (TAO_NO_COPY_OCTET_SEQUENCES == 0)
00327 
00328 // This doesn't work always for unexplained reason. At least
00329 // PortableServer::Active_Object_Map.cpp fails to compile with some compilers.
00330 // But I'm keeping this in for the moment so that it may be
00331 // resurrected if need be
00332 inline
00333 bool
00334 operator== (const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & lhs,
00335             const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & rhs)
00336 {
00337   ::CORBA::ULong const rlen = rhs.length ();
00338 
00339   if (rlen != lhs.length ())
00340     {
00341       return false;
00342     }
00343 
00344   const CORBA::Octet * rhs_buff = rhs.get_buffer ();
00345   const CORBA::Octet * lhs_buff = lhs.get_buffer ();
00346   const bool result = (ACE_OS::memcmp (lhs_buff, rhs_buff, rlen) == 0);
00347 
00348   return result;
00349 }
00350 
00351 inline
00352 bool
00353 operator!= (const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & lhs,
00354             const TAO_VERSIONED_NAMESPACE_NAME::TAO::unbounded_value_sequence<CORBA::Octet> & rhs)
00355 {
00356   return !(lhs == rhs);
00357 }
00358 #endif /* TAO_NO_COPY_OCTET_SEQUENCES==0 */
00359 
00360 #endif // guard_unbounded_octet_sequence_hpp

Generated on Tue Feb 2 17:37:53 2010 for TAO by  doxygen 1.4.7