front_idill/extern/fajran-npTuioClient/TuioClient/oscpack/osc/OscOutboundPacketStream.cpp
changeset 30 45c889eae324
parent 29 fcf435874395
child 31 2c7fc855eba8
equal deleted inserted replaced
29:fcf435874395 30:45c889eae324
     1 /*
       
     2     oscpack -- Open Sound Control packet manipulation library
       
     3     http://www.audiomulch.com/~rossb/oscpack
       
     4 
       
     5     Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
       
     6 
       
     7     Permission is hereby granted, free of charge, to any person obtaining
       
     8     a copy of this software and associated documentation files
       
     9     (the "Software"), to deal in the Software without restriction,
       
    10     including without limitation the rights to use, copy, modify, merge,
       
    11     publish, distribute, sublicense, and/or sell copies of the Software,
       
    12     and to permit persons to whom the Software is furnished to do so,
       
    13     subject to the following conditions:
       
    14 
       
    15     The above copyright notice and this permission notice shall be
       
    16     included in all copies or substantial portions of the Software.
       
    17 
       
    18     Any person wishing to distribute modifications to the Software is
       
    19     requested to send the modifications to the original developer so that
       
    20     they can be incorporated into the canonical version.
       
    21 
       
    22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    25     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
       
    26     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
       
    27     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
       
    28     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    29 */
       
    30 #include "OscOutboundPacketStream.h"
       
    31 
       
    32 #include <string.h>
       
    33 #include <stdlib.h>
       
    34 #include <assert.h>
       
    35 
       
    36 #if defined(__WIN32__) || defined(WIN32)
       
    37 #include <malloc.h> // for alloca
       
    38 #endif
       
    39 
       
    40 #include "OscHostEndianness.h"
       
    41 
       
    42 
       
    43 namespace osc{
       
    44 
       
    45 static void FromInt32( char *p, int32 x )
       
    46 {
       
    47 #ifdef OSC_HOST_LITTLE_ENDIAN
       
    48     union{
       
    49         osc::int32 i;
       
    50         char c[4];
       
    51     } u;
       
    52 
       
    53     u.i = x;
       
    54 
       
    55     p[3] = u.c[0];
       
    56     p[2] = u.c[1];
       
    57     p[1] = u.c[2];
       
    58     p[0] = u.c[3];
       
    59 #else
       
    60     *reinterpret_cast<int32*>(p) = x;
       
    61 #endif
       
    62 }
       
    63 
       
    64 
       
    65 static void FromUInt32( char *p, uint32 x )
       
    66 {
       
    67 #ifdef OSC_HOST_LITTLE_ENDIAN
       
    68     union{
       
    69         osc::uint32 i;
       
    70         char c[4];
       
    71     } u;
       
    72 
       
    73     u.i = x;
       
    74 
       
    75     p[3] = u.c[0];
       
    76     p[2] = u.c[1];
       
    77     p[1] = u.c[2];
       
    78     p[0] = u.c[3];
       
    79 #else
       
    80     *reinterpret_cast<uint32*>(p) = x;
       
    81 #endif
       
    82 }
       
    83 
       
    84 
       
    85 static void FromInt64( char *p, int64 x )
       
    86 {
       
    87 #ifdef OSC_HOST_LITTLE_ENDIAN
       
    88     union{
       
    89         osc::int64 i;
       
    90         char c[8];
       
    91     } u;
       
    92 
       
    93     u.i = x;
       
    94 
       
    95     p[7] = u.c[0];
       
    96     p[6] = u.c[1];
       
    97     p[5] = u.c[2];
       
    98     p[4] = u.c[3];
       
    99     p[3] = u.c[4];
       
   100     p[2] = u.c[5];
       
   101     p[1] = u.c[6];
       
   102     p[0] = u.c[7];
       
   103 #else
       
   104     *reinterpret_cast<int64*>(p) = x;
       
   105 #endif
       
   106 }
       
   107 
       
   108 
       
   109 static void FromUInt64( char *p, uint64 x )
       
   110 {
       
   111 #ifdef OSC_HOST_LITTLE_ENDIAN
       
   112     union{
       
   113         osc::uint64 i;
       
   114         char c[8];
       
   115     } u;
       
   116 
       
   117     u.i = x;
       
   118 
       
   119     p[7] = u.c[0];
       
   120     p[6] = u.c[1];
       
   121     p[5] = u.c[2];
       
   122     p[4] = u.c[3];
       
   123     p[3] = u.c[4];
       
   124     p[2] = u.c[5];
       
   125     p[1] = u.c[6];
       
   126     p[0] = u.c[7];
       
   127 #else
       
   128     *reinterpret_cast<uint64*>(p) = x;
       
   129 #endif
       
   130 }
       
   131 
       
   132 
       
   133 static inline long RoundUp4( long x )
       
   134 {
       
   135     return ((x-1) & (~0x03L)) + 4;
       
   136 }
       
   137 
       
   138 
       
   139 OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
       
   140     : data_( buffer )
       
   141     , end_( data_ + capacity )
       
   142     , typeTagsCurrent_( end_ )
       
   143     , messageCursor_( data_ )
       
   144     , argumentCurrent_( data_ )
       
   145     , elementSizePtr_( 0 )
       
   146     , messageIsInProgress_( false )
       
   147 {
       
   148 
       
   149 }
       
   150 
       
   151 
       
   152 OutboundPacketStream::~OutboundPacketStream()
       
   153 {
       
   154 
       
   155 }
       
   156 
       
   157 
       
   158 char *OutboundPacketStream::BeginElement( char *beginPtr )
       
   159 {
       
   160     if( elementSizePtr_ == 0 ){
       
   161 
       
   162         elementSizePtr_ = reinterpret_cast<uint32*>(data_);
       
   163 
       
   164         return beginPtr;
       
   165 
       
   166     }else{
       
   167         // store an offset to the old element size ptr in the element size slot
       
   168         // we store an offset rather than the actual pointer to be 64 bit clean.
       
   169         *reinterpret_cast<uint32*>(beginPtr) =
       
   170                 (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
       
   171 
       
   172         elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
       
   173 
       
   174         return beginPtr + 4;
       
   175     }
       
   176 }
       
   177 
       
   178 
       
   179 void OutboundPacketStream::EndElement( char *endPtr )
       
   180 {
       
   181     assert( elementSizePtr_ != 0 );
       
   182 
       
   183     if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
       
   184 
       
   185         elementSizePtr_ = 0;
       
   186 
       
   187     }else{
       
   188         // while building an element, an offset to the containing element's
       
   189         // size slot is stored in the elements size slot (or a ptr to data_
       
   190         // if there is no containing element). We retrieve that here
       
   191         uint32 *previousElementSizePtr =
       
   192                 (uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
       
   193 
       
   194         // then we store the element size in the slot, note that the element
       
   195         // size does not include the size slot, hence the - 4 below.
       
   196         uint32 elementSize =
       
   197                 (endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
       
   198         FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
       
   199 
       
   200         // finally, we reset the element size ptr to the containing element
       
   201         elementSizePtr_ = previousElementSizePtr;
       
   202     }
       
   203 }
       
   204 
       
   205 
       
   206 bool OutboundPacketStream::ElementSizeSlotRequired() const
       
   207 {
       
   208     return (elementSizePtr_ != 0);
       
   209 }
       
   210 
       
   211 
       
   212 void OutboundPacketStream::CheckForAvailableBundleSpace()
       
   213 {
       
   214     unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
       
   215 
       
   216     if( required > Capacity() )
       
   217         throw OutOfBufferMemoryException();
       
   218 }
       
   219 
       
   220 
       
   221 void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
       
   222 {
       
   223     // plus 4 for at least four bytes of type tag
       
   224      unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
       
   225             + RoundUp4(strlen(addressPattern) + 1) + 4;
       
   226 
       
   227     if( required > Capacity() )
       
   228         throw OutOfBufferMemoryException();
       
   229 }
       
   230 
       
   231 
       
   232 void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
       
   233 {
       
   234     // plus three for extra type tag, comma and null terminator
       
   235      unsigned long required = (argumentCurrent_ - data_) + argumentLength
       
   236             + RoundUp4( (end_ - typeTagsCurrent_) + 3 );
       
   237 
       
   238     if( required > Capacity() )
       
   239         throw OutOfBufferMemoryException();
       
   240 }
       
   241 
       
   242 
       
   243 void OutboundPacketStream::Clear()
       
   244 {
       
   245     typeTagsCurrent_ = end_;
       
   246     messageCursor_ = data_;
       
   247     argumentCurrent_ = data_;
       
   248     elementSizePtr_ = 0;
       
   249     messageIsInProgress_ = false;
       
   250 }
       
   251 
       
   252 
       
   253 unsigned int OutboundPacketStream::Capacity() const
       
   254 {
       
   255     return end_ - data_;
       
   256 }
       
   257 
       
   258 
       
   259 unsigned int OutboundPacketStream::Size() const
       
   260 {
       
   261     unsigned int result = argumentCurrent_ - data_;
       
   262     if( IsMessageInProgress() ){
       
   263         // account for the length of the type tag string. the total type tag
       
   264         // includes an initial comma, plus at least one terminating \0
       
   265         result += RoundUp4( (end_ - typeTagsCurrent_) + 2 );
       
   266     }
       
   267 
       
   268     return result;
       
   269 }
       
   270 
       
   271 
       
   272 const char *OutboundPacketStream::Data() const
       
   273 {
       
   274     return data_;
       
   275 }
       
   276 
       
   277 
       
   278 bool OutboundPacketStream::IsReady() const
       
   279 {
       
   280     return (!IsMessageInProgress() && !IsBundleInProgress());
       
   281 }
       
   282 
       
   283 
       
   284 bool OutboundPacketStream::IsMessageInProgress() const
       
   285 {
       
   286     return messageIsInProgress_;
       
   287 }
       
   288 
       
   289 
       
   290 bool OutboundPacketStream::IsBundleInProgress() const
       
   291 {
       
   292     return (elementSizePtr_ != 0);
       
   293 }
       
   294 
       
   295 
       
   296 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
       
   297 {
       
   298     if( IsMessageInProgress() )
       
   299         throw MessageInProgressException();
       
   300 
       
   301     CheckForAvailableBundleSpace();
       
   302 
       
   303     messageCursor_ = BeginElement( messageCursor_ );
       
   304 
       
   305     memcpy( messageCursor_, "#bundle\0", 8 );
       
   306     FromUInt64( messageCursor_ + 8, rhs.timeTag );
       
   307 
       
   308     messageCursor_ += 16;
       
   309     argumentCurrent_ = messageCursor_;
       
   310 
       
   311     return *this;
       
   312 }
       
   313 
       
   314 
       
   315 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
       
   316 {
       
   317     (void) rhs;
       
   318 
       
   319     if( !IsBundleInProgress() )
       
   320         throw BundleNotInProgressException();
       
   321     if( IsMessageInProgress() )
       
   322         throw MessageInProgressException();
       
   323 
       
   324     EndElement( messageCursor_ );
       
   325 
       
   326     return *this;
       
   327 }
       
   328 
       
   329 
       
   330 OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
       
   331 {
       
   332     if( IsMessageInProgress() )
       
   333         throw MessageInProgressException();
       
   334 
       
   335     CheckForAvailableMessageSpace( rhs.addressPattern );
       
   336 
       
   337     messageCursor_ = BeginElement( messageCursor_ );
       
   338 
       
   339     strcpy( messageCursor_, rhs.addressPattern );
       
   340     unsigned long rhsLength = strlen(rhs.addressPattern);
       
   341     messageCursor_ += rhsLength + 1;
       
   342 
       
   343     // zero pad to 4-byte boundary
       
   344     unsigned long i = rhsLength + 1;
       
   345     while( i & 0x3 ){
       
   346         *messageCursor_++ = '\0';
       
   347         ++i;
       
   348     }
       
   349 
       
   350     argumentCurrent_ = messageCursor_;
       
   351     typeTagsCurrent_ = end_;
       
   352 
       
   353     messageIsInProgress_ = true;
       
   354 
       
   355     return *this;
       
   356 }
       
   357 
       
   358 
       
   359 OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
       
   360 {
       
   361     (void) rhs;
       
   362 
       
   363     if( !IsMessageInProgress() )
       
   364         throw MessageNotInProgressException();
       
   365 
       
   366     int typeTagsCount = end_ - typeTagsCurrent_;
       
   367 
       
   368     if( typeTagsCount ){
       
   369 
       
   370         char *tempTypeTags = (char*)alloca(typeTagsCount);
       
   371         memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
       
   372 
       
   373         // slot size includes comma and null terminator
       
   374         int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
       
   375 
       
   376         uint32 argumentsSize = argumentCurrent_ - messageCursor_;
       
   377 
       
   378         memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
       
   379 
       
   380         messageCursor_[0] = ',';
       
   381         // copy type tags in reverse (really forward) order
       
   382         for( int i=0; i < typeTagsCount; ++i )
       
   383             messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
       
   384 
       
   385         char *p = messageCursor_ + 1 + typeTagsCount;
       
   386         for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
       
   387             *p++ = '\0';
       
   388 
       
   389         typeTagsCurrent_ = end_;
       
   390 
       
   391         // advance messageCursor_ for next message
       
   392         messageCursor_ += typeTagSlotSize + argumentsSize;
       
   393 
       
   394     }else{
       
   395         // send an empty type tags string
       
   396         memcpy( messageCursor_, ",\0\0\0", 4 );
       
   397 
       
   398         // advance messageCursor_ for next message
       
   399         messageCursor_ += 4;
       
   400     }
       
   401 
       
   402     argumentCurrent_ = messageCursor_;
       
   403 
       
   404     EndElement( messageCursor_ );
       
   405 
       
   406     messageIsInProgress_ = false;
       
   407 
       
   408     return *this;
       
   409 }
       
   410 
       
   411 
       
   412 OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
       
   413 {
       
   414     CheckForAvailableArgumentSpace(0);
       
   415 
       
   416     *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
       
   417 
       
   418     return *this;
       
   419 }
       
   420 
       
   421 
       
   422 OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
       
   423 {
       
   424     (void) rhs;
       
   425     CheckForAvailableArgumentSpace(0);
       
   426 
       
   427     *(--typeTagsCurrent_) = NIL_TYPE_TAG;
       
   428 
       
   429     return *this;
       
   430 }
       
   431 
       
   432 
       
   433 OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
       
   434 {
       
   435     (void) rhs;
       
   436     CheckForAvailableArgumentSpace(0);
       
   437 
       
   438     *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
       
   439 
       
   440     return *this;
       
   441 }
       
   442 
       
   443 
       
   444 OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
       
   445 {
       
   446     CheckForAvailableArgumentSpace(4);
       
   447 
       
   448     *(--typeTagsCurrent_) = INT32_TYPE_TAG;
       
   449     FromInt32( argumentCurrent_, rhs );
       
   450     argumentCurrent_ += 4;
       
   451 
       
   452     return *this;
       
   453 }
       
   454 
       
   455 
       
   456 OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
       
   457 {
       
   458     CheckForAvailableArgumentSpace(4);
       
   459 
       
   460     *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
       
   461 
       
   462 #ifdef OSC_HOST_LITTLE_ENDIAN
       
   463     union{
       
   464         float f;
       
   465         char c[4];
       
   466     } u;
       
   467 
       
   468     u.f = rhs;
       
   469 
       
   470     argumentCurrent_[3] = u.c[0];
       
   471     argumentCurrent_[2] = u.c[1];
       
   472     argumentCurrent_[1] = u.c[2];
       
   473     argumentCurrent_[0] = u.c[3];
       
   474 #else
       
   475     *reinterpret_cast<float*>(argumentCurrent_) = rhs;
       
   476 #endif
       
   477 
       
   478     argumentCurrent_ += 4;
       
   479 
       
   480     return *this;
       
   481 }
       
   482 
       
   483 
       
   484 OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
       
   485 {
       
   486     CheckForAvailableArgumentSpace(4);
       
   487 
       
   488     *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
       
   489     FromInt32( argumentCurrent_, rhs );
       
   490     argumentCurrent_ += 4;
       
   491 
       
   492     return *this;
       
   493 }
       
   494 
       
   495 
       
   496 OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
       
   497 {
       
   498     CheckForAvailableArgumentSpace(4);
       
   499 
       
   500     *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
       
   501     FromUInt32( argumentCurrent_, rhs );
       
   502     argumentCurrent_ += 4;
       
   503 
       
   504     return *this;
       
   505 }
       
   506 
       
   507 
       
   508 OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
       
   509 {
       
   510     CheckForAvailableArgumentSpace(4);
       
   511 
       
   512     *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
       
   513     FromUInt32( argumentCurrent_, rhs );
       
   514     argumentCurrent_ += 4;
       
   515 
       
   516     return *this;
       
   517 }
       
   518 
       
   519 
       
   520 OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
       
   521 {
       
   522     CheckForAvailableArgumentSpace(8);
       
   523 
       
   524     *(--typeTagsCurrent_) = INT64_TYPE_TAG;
       
   525     FromInt64( argumentCurrent_, rhs );
       
   526     argumentCurrent_ += 8;
       
   527 
       
   528     return *this;
       
   529 }
       
   530 
       
   531 
       
   532 OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
       
   533 {
       
   534     CheckForAvailableArgumentSpace(8);
       
   535 
       
   536     *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
       
   537     FromUInt64( argumentCurrent_, rhs );
       
   538     argumentCurrent_ += 8;
       
   539 
       
   540     return *this;
       
   541 }
       
   542 
       
   543 
       
   544 OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
       
   545 {
       
   546     CheckForAvailableArgumentSpace(8);
       
   547 
       
   548     *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
       
   549 
       
   550 #ifdef OSC_HOST_LITTLE_ENDIAN
       
   551     union{
       
   552         double f;
       
   553         char c[8];
       
   554     } u;
       
   555 
       
   556     u.f = rhs;
       
   557 
       
   558     argumentCurrent_[7] = u.c[0];
       
   559     argumentCurrent_[6] = u.c[1];
       
   560     argumentCurrent_[5] = u.c[2];
       
   561     argumentCurrent_[4] = u.c[3];
       
   562     argumentCurrent_[3] = u.c[4];
       
   563     argumentCurrent_[2] = u.c[5];
       
   564     argumentCurrent_[1] = u.c[6];
       
   565     argumentCurrent_[0] = u.c[7];
       
   566 #else
       
   567     *reinterpret_cast<double*>(argumentCurrent_) = rhs;
       
   568 #endif
       
   569 
       
   570     argumentCurrent_ += 8;
       
   571 
       
   572     return *this;
       
   573 }
       
   574 
       
   575 
       
   576 OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
       
   577 {
       
   578     CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
       
   579 
       
   580     *(--typeTagsCurrent_) = STRING_TYPE_TAG;
       
   581     strcpy( argumentCurrent_, rhs );
       
   582     unsigned long rhsLength = strlen(rhs);
       
   583     argumentCurrent_ += rhsLength + 1;
       
   584 
       
   585     // zero pad to 4-byte boundary
       
   586     unsigned long i = rhsLength + 1;
       
   587     while( i & 0x3 ){
       
   588         *argumentCurrent_++ = '\0';
       
   589         ++i;
       
   590     }
       
   591 
       
   592     return *this;
       
   593 }
       
   594 
       
   595 
       
   596 OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
       
   597 {
       
   598     CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) );
       
   599 
       
   600     *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
       
   601     strcpy( argumentCurrent_, rhs );
       
   602     unsigned long rhsLength = strlen(rhs);
       
   603     argumentCurrent_ += rhsLength + 1;
       
   604 
       
   605     // zero pad to 4-byte boundary
       
   606     unsigned long i = rhsLength + 1;
       
   607     while( i & 0x3 ){
       
   608         *argumentCurrent_++ = '\0';
       
   609         ++i;
       
   610     }
       
   611 
       
   612     return *this;
       
   613 }
       
   614 
       
   615 
       
   616 OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
       
   617 {
       
   618     CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
       
   619 
       
   620     *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
       
   621     FromUInt32( argumentCurrent_, rhs.size );
       
   622     argumentCurrent_ += 4;
       
   623     
       
   624     memcpy( argumentCurrent_, rhs.data, rhs.size );
       
   625     argumentCurrent_ += rhs.size;
       
   626 
       
   627     // zero pad to 4-byte boundary
       
   628     unsigned long i = rhs.size;
       
   629     while( i & 0x3 ){
       
   630         *argumentCurrent_++ = '\0';
       
   631         ++i;
       
   632     }
       
   633 
       
   634     return *this;
       
   635 }
       
   636 
       
   637 } // namespace osc
       
   638 
       
   639