<commit_before>// @(#)root/net:$Id$
// Author: Fons Rademakers   19/12/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TMessage                                                             //
//                                                                      //
// Message buffer class used for serializing objects and sending them   //
// over a network. This class inherits from TBuffer the basic I/O       //
// serializer.                                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TMessage.h"
#include "TVirtualStreamerInfo.h"
#include "Bytes.h"
#include "TFile.h"
#include "TProcessID.h"

extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
const Int_t kMAXBUF = 0xffffff;

Bool_t TMessage::fgEvolution = kFALSE;

ClassImp(TMessage)

//______________________________________________________________________________
TMessage::TMessage(UInt_t what) : TBufferFile(TBuffer::kWrite)
{
   // Create a TMessage object for storing objects. The "what" integer
   // describes the type of message. Predifined ROOT system message types
   // can be found in MessageTypes.h. Make sure your own message types are
   // unique from the ROOT defined message types (i.e. 0 - 10000 are
   // reserved by ROOT). In case you OR "what" with kMESS_ACK, the message
   // will wait for an acknowledgement from the remote side. This makes
   // the sending process synchronous. In case you OR "what" with kMESS_ZIP,
   // the message will be compressed in TSocket using the zip algorithm
   // (only if message is > 256 bytes).

   // space at the beginning of the message reserved for the message length
   UInt_t   reserved = 0;
   *this << reserved;

   fWhat  = what;
   *this << what;

   fClass      = 0;
   fCompress   = 0;
   fBufComp    = 0;
   fBufCompCur = 0;
   fCompPos    = 0;
   fInfos      = 0;
   fEvolution  = kFALSE;

   SetBit(kCannotHandleMemberWiseStreaming);
}

//______________________________________________________________________________
TMessage::TMessage(void *buf, Int_t bufsize) : TBufferFile(TBuffer::kRead, bufsize, buf)
{
   // Create a TMessage object for reading objects. The objects will be
   // read from buf. Use the What() method to get the message type.

   // skip space at the beginning of the message reserved for the message length
   fBufCur += sizeof(UInt_t);

   *this >> fWhat;

   fCompress   = 0;
   fBufComp    = 0;
   fBufCompCur = 0;
   fCompPos    = 0;
   fInfos      = 0;
   fEvolution  = kFALSE;

   if (fWhat & kMESS_ZIP) {
      // if buffer has kMESS_ZIP set, move it to fBufComp and uncompress
      fBufComp    = fBuffer;
      fBufCompCur = fBuffer + bufsize;
      fBuffer     = 0;
      Uncompress();
   }

   if (fWhat == kMESS_OBJECT) {
      InitMap();
      fClass = ReadClass();     // get first the class stored in message
      SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
      ResetMap();
   } else {
      fClass = 0;
   }
}

//______________________________________________________________________________
TMessage::~TMessage()
{
   // Clean up compression buffer.

   delete [] fBufComp;
   delete fInfos;
}

//______________________________________________________________________________
void TMessage::EnableSchemaEvolutionForAll(Bool_t enable)
{
   // Static function enabling or disabling the automatic schema evolution.
   // By default schema evolution support is off.

   fgEvolution = enable;
}

//______________________________________________________________________________
Bool_t TMessage::UsesSchemaEvolutionForAll()
{
   // Static function returning status of global schema evolution.

   return fgEvolution;
}

//______________________________________________________________________________
void TMessage::ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t /* force */)
{
   // Force writing the TStreamerInfo to the message.

   if (fgEvolution || fEvolution) fInfos->Add(info);
}

//______________________________________________________________________________
void TMessage::Forward()
{
   // Change a buffer that was received into one that can be send, i.e.
   // forward a just received message.

   if (IsReading()) {
      SetWriteMode();
      SetBufferOffset(fBufSize);
      SetBit(kCannotHandleMemberWiseStreaming);

      if (fBufComp) {
         fCompPos = fBufCur;
      }
   }
}

//______________________________________________________________________________
void TMessage::IncrementLevel(TVirtualStreamerInfo *info)
{
   // Increment level.

   TBufferFile::IncrementLevel(info);

   if (fgEvolution || fEvolution) fInfos->Add(info);
}

//______________________________________________________________________________
void TMessage::Reset()
{
   // Reset the message buffer so we can use (i.e. fill) it again.

   SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
   ResetMap();

   if (fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }
}

//______________________________________________________________________________
void TMessage::SetLength() const
{
   // Set the message length at the beginning of the message buffer.
   // This method is only called by TSocket::Send().

   if (IsWriting()) {
      char *buf = Buffer();
      tobuf(buf, (UInt_t)(Length() - sizeof(UInt_t)));

      if (fBufComp) {
         buf = fBufComp;
         tobuf(buf, (UInt_t)(CompLength() - sizeof(UInt_t)));
      }
   }
}

//______________________________________________________________________________
void TMessage::SetWhat(UInt_t what)
{
   // Using this method one can change the message type a-posteriory.
   // In case you OR "what" with kMESS_ACK, the message will wait for
   // an acknowledgement from the remote side. This makes the sending
   // process synchronous.

   fWhat = what;

   char *buf = Buffer();
   buf += sizeof(UInt_t);   // skip reserved length space
   tobuf(buf, what);

   if (fBufComp) {
      buf = fBufComp;
      buf += sizeof(UInt_t);   // skip reserved length space
      tobuf(buf, what | kMESS_ZIP);
   }
}

//______________________________________________________________________________
void TMessage::SetCompressionLevel(Int_t level)
{
   // Set the message compression level. Can be between 0 and 9 with 0
   // being no compression and 9 maximum compression. In general the default
   // level of 1 is the best compromise between achieved compression and
   // cpu time. Compression will only happen when the message is > 256 bytes.

   if (level < 0) level = 0;
   if (level > 9) level = 9;

   if (level != fCompress && fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }
   fCompress = level;
}

//______________________________________________________________________________
Int_t TMessage::Compress()
{
   // Compress the message. The message will only be compressed if the
   // compression level > 0 and the if the message is > 256 bytes.
   // Returns -1 in case of error (when compression fails or
   // when the message increases in size in some pathological cases),
   // otherwise returns 0.

   if (fCompress == 0) {
      // no compression specified
      if (fBufComp) {
         delete [] fBufComp;
         fBufComp    = 0;
         fBufCompCur = 0;
         fCompPos    = 0;
      }
      return 0;
   }

   if (fBufComp && fCompPos == fBufCur) {
      // the message was already compressed
      return 0;
   }

   // remove any existing compressed buffer before compressing modified message
   if (fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }

   if (Length() <= (Int_t)(256 + 2*sizeof(UInt_t))) {
      // this message is too small to be compressed
      return 0;
   }

   Int_t hdrlen   = 2*sizeof(UInt_t);
   Int_t messlen  = Length() - hdrlen;
   Int_t nbuffers = messlen / kMAXBUF;
   Int_t chdrlen  = 3*sizeof(UInt_t);   // compressed buffer header length
   Int_t buflen   = TMath::Max(512, chdrlen + messlen + 9*nbuffers);
   fBufComp       = new char[buflen];
   char *messbuf  = Buffer() + hdrlen;
   char *bufcur   = fBufComp + chdrlen;
   Int_t noutot   = 0;
   Int_t nzip     = 0;
   Int_t nout, bufmax;
   for (Int_t i = 0; i <= nbuffers; i++) {
      if (i == nbuffers)
         bufmax = messlen - nzip;
      else
         bufmax = kMAXBUF;
      R__zip(fCompress, &bufmax, messbuf, &bufmax, bufcur, &nout);
      if (nout == 0 || nout >= messlen) {
         //this happens when the buffer cannot be compressed
         delete [] fBufComp;
         fBufComp    = 0;
         fBufCompCur = 0;
         fCompPos    = 0;
         return -1;
      }
      bufcur  += nout;
      noutot  += nout;
      messbuf += kMAXBUF;
      nzip    += kMAXBUF;
   }
   fBufCompCur = bufcur;
   fCompPos    = fBufCur;

   bufcur = fBufComp;
   tobuf(bufcur, (UInt_t)(CompLength() - sizeof(UInt_t)));
   Int_t what = fWhat | kMESS_ZIP;
   tobuf(bufcur, what);
   tobuf(bufcur, Length());    // original uncompressed buffer length

   return 0;
}

//______________________________________________________________________________
Int_t TMessage::Uncompress()
{
   // Uncompress the message. The message will only be uncompressed when
   // kMESS_ZIP is set. Returns -1 in case of error, 0 otherwise.

   if (!fBufComp || !(fWhat & kMESS_ZIP))
      return -1;

   Int_t buflen;
   Int_t hdrlen = 2*sizeof(UInt_t);
   char *bufcur1 = fBufComp + hdrlen;
   frombuf(bufcur1, &buflen);
   UChar_t *bufcur = (UChar_t*)bufcur1;
   fBuffer  = new char[buflen];
   fBufSize = buflen;
   fBufCur  = fBuffer + sizeof(UInt_t) + sizeof(fWhat);
   fBufMax  = fBuffer + fBufSize;
   char *messbuf = fBuffer + hdrlen;

   Int_t nin, nout, nbuf;
   Int_t noutot = 0;
   while (1) {
      nin  = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
      nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
      R__unzip(&nin, bufcur, &nbuf, messbuf, &nout);
      if (!nout) break;
      noutot += nout;
      if (noutot >= buflen - hdrlen) break;
      bufcur  += nin;
      messbuf += nout;
   }

   fWhat &= ~kMESS_ZIP;
   fCompress = 1;

   return 0;
}

//______________________________________________________________________________
void TMessage::WriteObject(const TObject *obj)
{
   // Write object to message buffer.
   // When support for schema evolution is enabled the list of TStreamerInfo
   // used to stream this object is kept in fInfos. This information is used
   // by TSocket::Send that sends this list through the socket. This list is in
   // turn used by TSocket::Recv to store the TStreamerInfo objects in the
   // relevant TClass in case the TClass does not know yet about a particular
   // class version. This feature is implemented to support clients and servers
   // with either different ROOT versions or different user classes versions.

   if (fgEvolution || fEvolution) {
      if (fInfos)
         fInfos->Clear();
      else
         fInfos = new TList();
   }

   fBitsPIDs.ResetAllBits();
   WriteObjectAny(obj, TObject::Class());
}

//______________________________________________________________________________
UShort_t TMessage::WriteProcessID(TProcessID *pid)
{
   // Check if the ProcessID pid is already in the message.
   // If not, then
   //   -mark bit 0 of fBitsPIDs to indicate that a ProcessID has been found
   //   -mark bit uid+1 where uid id the uid of the ProcessID

   if (fBitsPIDs.TestBitNumber(0)) return 0;
   fBitsPIDs.SetBitNumber(0);
   UInt_t uid = pid->GetUniqueID();
   fBitsPIDs.SetBitNumber(uid+1);
   return 1;
}
<commit_msg>add protection against TProcessID pid being 0 in WriteProcessID(). Should fix ALICE CAF issue.<commit_after>// @(#)root/net:$Id$
// Author: Fons Rademakers   19/12/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TMessage                                                             //
//                                                                      //
// Message buffer class used for serializing objects and sending them   //
// over a network. This class inherits from TBuffer the basic I/O       //
// serializer.                                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TMessage.h"
#include "TVirtualStreamerInfo.h"
#include "Bytes.h"
#include "TFile.h"
#include "TProcessID.h"

extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
const Int_t kMAXBUF = 0xffffff;

Bool_t TMessage::fgEvolution = kFALSE;

ClassImp(TMessage)

//______________________________________________________________________________
TMessage::TMessage(UInt_t what) : TBufferFile(TBuffer::kWrite)
{
   // Create a TMessage object for storing objects. The "what" integer
   // describes the type of message. Predifined ROOT system message types
   // can be found in MessageTypes.h. Make sure your own message types are
   // unique from the ROOT defined message types (i.e. 0 - 10000 are
   // reserved by ROOT). In case you OR "what" with kMESS_ACK, the message
   // will wait for an acknowledgement from the remote side. This makes
   // the sending process synchronous. In case you OR "what" with kMESS_ZIP,
   // the message will be compressed in TSocket using the zip algorithm
   // (only if message is > 256 bytes).

   // space at the beginning of the message reserved for the message length
   UInt_t   reserved = 0;
   *this << reserved;

   fWhat  = what;
   *this << what;

   fClass      = 0;
   fCompress   = 0;
   fBufComp    = 0;
   fBufCompCur = 0;
   fCompPos    = 0;
   fInfos      = 0;
   fEvolution  = kFALSE;

   SetBit(kCannotHandleMemberWiseStreaming);
}

//______________________________________________________________________________
TMessage::TMessage(void *buf, Int_t bufsize) : TBufferFile(TBuffer::kRead, bufsize, buf)
{
   // Create a TMessage object for reading objects. The objects will be
   // read from buf. Use the What() method to get the message type.

   // skip space at the beginning of the message reserved for the message length
   fBufCur += sizeof(UInt_t);

   *this >> fWhat;

   fCompress   = 0;
   fBufComp    = 0;
   fBufCompCur = 0;
   fCompPos    = 0;
   fInfos      = 0;
   fEvolution  = kFALSE;

   if (fWhat & kMESS_ZIP) {
      // if buffer has kMESS_ZIP set, move it to fBufComp and uncompress
      fBufComp    = fBuffer;
      fBufCompCur = fBuffer + bufsize;
      fBuffer     = 0;
      Uncompress();
   }

   if (fWhat == kMESS_OBJECT) {
      InitMap();
      fClass = ReadClass();     // get first the class stored in message
      SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
      ResetMap();
   } else {
      fClass = 0;
   }
}

//______________________________________________________________________________
TMessage::~TMessage()
{
   // Clean up compression buffer.

   delete [] fBufComp;
   delete fInfos;
}

//______________________________________________________________________________
void TMessage::EnableSchemaEvolutionForAll(Bool_t enable)
{
   // Static function enabling or disabling the automatic schema evolution.
   // By default schema evolution support is off.

   fgEvolution = enable;
}

//______________________________________________________________________________
Bool_t TMessage::UsesSchemaEvolutionForAll()
{
   // Static function returning status of global schema evolution.

   return fgEvolution;
}

//______________________________________________________________________________
void TMessage::ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t /* force */)
{
   // Force writing the TStreamerInfo to the message.

   if (fgEvolution || fEvolution) fInfos->Add(info);
}

//______________________________________________________________________________
void TMessage::Forward()
{
   // Change a buffer that was received into one that can be send, i.e.
   // forward a just received message.

   if (IsReading()) {
      SetWriteMode();
      SetBufferOffset(fBufSize);
      SetBit(kCannotHandleMemberWiseStreaming);

      if (fBufComp) {
         fCompPos = fBufCur;
      }
   }
}

//______________________________________________________________________________
void TMessage::IncrementLevel(TVirtualStreamerInfo *info)
{
   // Increment level.

   TBufferFile::IncrementLevel(info);

   if (fgEvolution || fEvolution) fInfos->Add(info);
}

//______________________________________________________________________________
void TMessage::Reset()
{
   // Reset the message buffer so we can use (i.e. fill) it again.

   SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
   ResetMap();

   if (fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }
}

//______________________________________________________________________________
void TMessage::SetLength() const
{
   // Set the message length at the beginning of the message buffer.
   // This method is only called by TSocket::Send().

   if (IsWriting()) {
      char *buf = Buffer();
      tobuf(buf, (UInt_t)(Length() - sizeof(UInt_t)));

      if (fBufComp) {
         buf = fBufComp;
         tobuf(buf, (UInt_t)(CompLength() - sizeof(UInt_t)));
      }
   }
}

//______________________________________________________________________________
void TMessage::SetWhat(UInt_t what)
{
   // Using this method one can change the message type a-posteriory.
   // In case you OR "what" with kMESS_ACK, the message will wait for
   // an acknowledgement from the remote side. This makes the sending
   // process synchronous.

   fWhat = what;

   char *buf = Buffer();
   buf += sizeof(UInt_t);   // skip reserved length space
   tobuf(buf, what);

   if (fBufComp) {
      buf = fBufComp;
      buf += sizeof(UInt_t);   // skip reserved length space
      tobuf(buf, what | kMESS_ZIP);
   }
}

//______________________________________________________________________________
void TMessage::SetCompressionLevel(Int_t level)
{
   // Set the message compression level. Can be between 0 and 9 with 0
   // being no compression and 9 maximum compression. In general the default
   // level of 1 is the best compromise between achieved compression and
   // cpu time. Compression will only happen when the message is > 256 bytes.

   if (level < 0) level = 0;
   if (level > 9) level = 9;

   if (level != fCompress && fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }
   fCompress = level;
}

//______________________________________________________________________________
Int_t TMessage::Compress()
{
   // Compress the message. The message will only be compressed if the
   // compression level > 0 and the if the message is > 256 bytes.
   // Returns -1 in case of error (when compression fails or
   // when the message increases in size in some pathological cases),
   // otherwise returns 0.

   if (fCompress == 0) {
      // no compression specified
      if (fBufComp) {
         delete [] fBufComp;
         fBufComp    = 0;
         fBufCompCur = 0;
         fCompPos    = 0;
      }
      return 0;
   }

   if (fBufComp && fCompPos == fBufCur) {
      // the message was already compressed
      return 0;
   }

   // remove any existing compressed buffer before compressing modified message
   if (fBufComp) {
      delete [] fBufComp;
      fBufComp    = 0;
      fBufCompCur = 0;
      fCompPos    = 0;
   }

   if (Length() <= (Int_t)(256 + 2*sizeof(UInt_t))) {
      // this message is too small to be compressed
      return 0;
   }

   Int_t hdrlen   = 2*sizeof(UInt_t);
   Int_t messlen  = Length() - hdrlen;
   Int_t nbuffers = messlen / kMAXBUF;
   Int_t chdrlen  = 3*sizeof(UInt_t);   // compressed buffer header length
   Int_t buflen   = TMath::Max(512, chdrlen + messlen + 9*nbuffers);
   fBufComp       = new char[buflen];
   char *messbuf  = Buffer() + hdrlen;
   char *bufcur   = fBufComp + chdrlen;
   Int_t noutot   = 0;
   Int_t nzip     = 0;
   Int_t nout, bufmax;
   for (Int_t i = 0; i <= nbuffers; i++) {
      if (i == nbuffers)
         bufmax = messlen - nzip;
      else
         bufmax = kMAXBUF;
      R__zip(fCompress, &bufmax, messbuf, &bufmax, bufcur, &nout);
      if (nout == 0 || nout >= messlen) {
         //this happens when the buffer cannot be compressed
         delete [] fBufComp;
         fBufComp    = 0;
         fBufCompCur = 0;
         fCompPos    = 0;
         return -1;
      }
      bufcur  += nout;
      noutot  += nout;
      messbuf += kMAXBUF;
      nzip    += kMAXBUF;
   }
   fBufCompCur = bufcur;
   fCompPos    = fBufCur;

   bufcur = fBufComp;
   tobuf(bufcur, (UInt_t)(CompLength() - sizeof(UInt_t)));
   Int_t what = fWhat | kMESS_ZIP;
   tobuf(bufcur, what);
   tobuf(bufcur, Length());    // original uncompressed buffer length

   return 0;
}

//______________________________________________________________________________
Int_t TMessage::Uncompress()
{
   // Uncompress the message. The message will only be uncompressed when
   // kMESS_ZIP is set. Returns -1 in case of error, 0 otherwise.

   if (!fBufComp || !(fWhat & kMESS_ZIP))
      return -1;

   Int_t buflen;
   Int_t hdrlen = 2*sizeof(UInt_t);
   char *bufcur1 = fBufComp + hdrlen;
   frombuf(bufcur1, &buflen);
   UChar_t *bufcur = (UChar_t*)bufcur1;
   fBuffer  = new char[buflen];
   fBufSize = buflen;
   fBufCur  = fBuffer + sizeof(UInt_t) + sizeof(fWhat);
   fBufMax  = fBuffer + fBufSize;
   char *messbuf = fBuffer + hdrlen;

   Int_t nin, nout, nbuf;
   Int_t noutot = 0;
   while (1) {
      nin  = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
      nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
      R__unzip(&nin, bufcur, &nbuf, messbuf, &nout);
      if (!nout) break;
      noutot += nout;
      if (noutot >= buflen - hdrlen) break;
      bufcur  += nin;
      messbuf += nout;
   }

   fWhat &= ~kMESS_ZIP;
   fCompress = 1;

   return 0;
}

//______________________________________________________________________________
void TMessage::WriteObject(const TObject *obj)
{
   // Write object to message buffer.
   // When support for schema evolution is enabled the list of TStreamerInfo
   // used to stream this object is kept in fInfos. This information is used
   // by TSocket::Send that sends this list through the socket. This list is in
   // turn used by TSocket::Recv to store the TStreamerInfo objects in the
   // relevant TClass in case the TClass does not know yet about a particular
   // class version. This feature is implemented to support clients and servers
   // with either different ROOT versions or different user classes versions.

   if (fgEvolution || fEvolution) {
      if (fInfos)
         fInfos->Clear();
      else
         fInfos = new TList();
   }

   fBitsPIDs.ResetAllBits();
   WriteObjectAny(obj, TObject::Class());
}

//______________________________________________________________________________
UShort_t TMessage::WriteProcessID(TProcessID *pid)
{
   // Check if the ProcessID pid is already in the message.
   // If not, then:
   //   - mark bit 0 of fBitsPIDs to indicate that a ProcessID has been found
   //   - mark bit uid+1 where uid id the uid of the ProcessID

   if (fBitsPIDs.TestBitNumber(0)) return 0;
   if (!pid)
      pid = TProcessID::GetPID();
   if (!pid) return 0;
   fBitsPIDs.SetBitNumber(0);
   UInt_t uid = pid->GetUniqueID();
   fBitsPIDs.SetBitNumber(uid+1);
   return 1;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/python_utils.h"

#include "base/base_paths.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"

const char kPythonPathEnv[] = "PYTHONPATH";

void AppendToPythonPath(const FilePath& dir) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  std::string old_path;
  std::string dir_path;
#if defined(OS_WIN)
  dir_path = WideToUTF8(dir.value());
#elif defined(OS_POSIX)
  dir_path = dir.value();
#endif
  if (!env->GetVar(kPythonPathEnv, &old_path)) {
    env->SetVar(kPythonPathEnv, dir_path.c_str());
  } else if (old_path.find(dir_path) == std::string::npos) {
    std::string new_path(old_path);
#if defined(OS_WIN)
    new_path.append(";");
#elif defined(OS_POSIX)
    new_path.append(":");
#endif
    new_path.append(dir_path.c_str());
    env->SetVar(kPythonPathEnv, new_path);
  }
}

namespace {

// Search for |to_try|, rolling up the directory tree from
// |start_dir|.  If found, return true and put the path to |to_try| in
// |out_dir|.  If not, return false and leave |out_dir| untouched.
bool TryRelativeToDir(const FilePath& start_dir,
                      const FilePath& to_try,
                      FilePath* out_dir) {
  FilePath dir(start_dir);
  while (!file_util::DirectoryExists(dir.Append(to_try))) {
    FilePath parent = dir.DirName();
    if (parent == dir) {
      // We hit the root directory.
      return false;
    }
    dir = parent;
  }
  *out_dir = dir;
  return true;
}

}  // namespace

bool GetPyProtoPath(FilePath* dir) {
  // Locate the Python code generated by the protocol buffers compiler.
  FilePath generated_code_dir;
  if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
    LOG(ERROR) << "Can't find " << generated_code_dir.value();
    return false;
  }

  const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));

#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
  FilePath source_dir;
  if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) {
    LOG(ERROR) << "Can't find " << source_dir.value();
    return false;
  }
  // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep
  // into the Release/ (or Debug/) directory and we can't depend on
  // how far down it goes. So we walk upwards from DIR_EXE until we
  // find a likely looking spot.
  if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
    LOG(WARNING) << "Can't find " << kPyProto.value()
                 << " next to " << generated_code_dir.value();
    // On Chrome OS, we may have installed the test binaries and support tools
    // in a wholly separate location, relative to DIR_SOURCE_ROOT.  We'll want
    // to do a similar investigation from that point as well.
    generated_code_dir = source_dir
        .Append(FILE_PATH_LITERAL("out"))
        .Append(FILE_PATH_LITERAL("Release"));
    if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
      LOG(WARNING) << "Can't find " << kPyProto.value()
                   << " next to " << generated_code_dir.value();
      return false;
    }
  }
  generated_code_dir = *dir;
#endif
  *dir = generated_code_dir.Append(kPyProto);
  VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value();
  return true;
}

bool GetPythonRunTime(FilePath* dir) {
#if defined(OS_WIN)
  if (!PathService::Get(base::DIR_SOURCE_ROOT, dir))
    return false;
  *dir = dir->Append(FILE_PATH_LITERAL("third_party"))
      .Append(FILE_PATH_LITERAL("python_26"))
      .Append(FILE_PATH_LITERAL("python.exe"));
#elif defined(OS_POSIX)
  *dir = FilePath("python");
#endif
  return true;
}
<commit_msg>Revert "Set PYTHON_PATH at TestServer Init() instead of Start()"<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/python_utils.h"

#include "base/base_paths.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"

const char kPythonPathEnv[] = "PYTHONPATH";

void AppendToPythonPath(const FilePath& dir) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  std::string old_path;
  std::string dir_path;
#if defined(OS_WIN)
  dir_path = WideToUTF8(dir.value());
#elif defined(OS_POSIX)
  dir_path = dir.value();
#endif
  if (!env->GetVar(kPythonPathEnv, &old_path)) {
    env->SetVar(kPythonPathEnv, dir_path.c_str());
  } else if (old_path.find(dir_path) == std::string::npos) {
    std::string new_path(old_path);
#if defined(OS_WIN)
    new_path.append(";");
#elif defined(OS_POSIX)
    new_path.append(":");
#endif
    new_path.append(dir_path.c_str());
    env->SetVar(kPythonPathEnv, new_path);
  }
}

bool GetPyProtoPath(FilePath* dir) {
  // Locate the Python code generated by the protocol buffers compiler.
  FilePath generated_code_dir;
  if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
    return false;
  }

  const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));

#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
  // On Mac and Chrome OS, DIR_EXE might be pointing deep into the Release/
  // (or Debug/) directory and we can't depend on how far down it goes. So we
  // walk upwards from DIR_EXE until we find a likely looking spot.
  while (!file_util::DirectoryExists(generated_code_dir.Append(kPyProto))) {
    FilePath parent = generated_code_dir.DirName();
    if (parent == generated_code_dir) {
      // We hit the root directory. Maybe we didn't build any targets which
      // produced Python protocol buffers.
      PathService::Get(base::DIR_EXE, &generated_code_dir);
      return false;
    }
    generated_code_dir = parent;
  }
#endif
  *dir = generated_code_dir.Append(kPyProto);
  return true;
}

bool GetPythonRunTime(FilePath* dir) {
#if defined(OS_WIN)
  if (!PathService::Get(base::DIR_SOURCE_ROOT, dir))
    return false;
  *dir = dir->Append(FILE_PATH_LITERAL("third_party"))
      .Append(FILE_PATH_LITERAL("python_26"))
      .Append(FILE_PATH_LITERAL("python.exe"));
#elif defined(OS_POSIX)
  *dir = FilePath("python");
#endif
  return true;
}
<|endoftext|>


<commit_before><commit_msg>refine YAMC_DEBUG_TRACING log (fair_shared_mutex.hpp)<commit_after><|endoftext|>


<commit_before>//===-- ProfilePaths.cpp - interface to insert instrumentation ---*- C++ -*--=//
//
// This inserts intrumentation for counting
// execution of paths though a given function
// Its implemented as a "Function" Pass, and called using opt
//
// This pass is implemented by using algorithms similar to
// 1."Efficient Path Profiling": Ball, T. and Larus, J. R.,
// Proceedings of Micro-29, Dec 1996, Paris, France.
// 2."Efficiently Counting Program events with support for on-line
//   "queries": Ball T., ACM Transactions on Programming Languages
//   and systems, Sep 1994.
//
// The algorithms work on a Graph constructed over the nodes
// made from Basic Blocks: The transformations then take place on
// the constucted graph (implementation in Graph.cpp and GraphAuxillary.cpp)
// and finally, appropriate instrumentation is placed over suitable edges.
// (code inserted through EdgeCode.cpp).
//
// The algorithm inserts code such that every acyclic path in the CFG
// of a function is identified through a unique number. the code insertion
// is optimal in the sense that its inserted over a minimal set of edges. Also,
// the algorithm makes sure than initialization, path increment and counter
// update can be collapsed into minimum number of edges.
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Support/CFG.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/Transforms/Instrumentation/Graph.h"
#include <iostream>
#include <fstream>

using std::vector;

struct ProfilePaths : public FunctionPass {
  bool runOnFunction(Function &F);

  // Before this pass, make sure that there is only one
  // entry and only one exit node for the function in the CFG of the function
  //
  void ProfilePaths::getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<UnifyFunctionExitNodes>();
  }
};

static RegisterOpt<ProfilePaths> X("paths", "Profile Paths");

// createProfilePathsPass - Create a new pass to add path profiling
//
Pass *createProfilePathsPass() {
  return new ProfilePaths();
}

static Node *findBB(std::vector<Node *> &st, BasicBlock *BB){
  for(std::vector<Node *>::iterator si=st.begin(); si!=st.end(); ++si){
    if(((*si)->getElement())==BB){
      return *si;
    }
  }
  return NULL;
}

//Per function pass for inserting counters and trigger code
bool ProfilePaths::runOnFunction(Function &F){

  static int mn = -1;

  if(F.isExternal()) {
    return false;
  }

  //std::cerr<<"Instrumenting\n-----------------\n";
  //std::cerr<<F;
  //increment counter for instrumented functions. mn is now function#
  mn++;

  //std::cerr<<"MN = "<<mn<<"\n";;
  //std::cerr<<F;

  // Transform the cfg s.t. we have just one exit node
  BasicBlock *ExitNode = getAnalysis<UnifyFunctionExitNodes>().getExitNode();

  //iterating over BBs and making graph
  std::vector<Node *> nodes;
  std::vector<Edge> edges;

  Node *tmp;
  Node *exitNode, *startNode;

  // The nodes must be uniquesly identified:
  // That is, no two nodes must hav same BB*

  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE; ++BB) {
    Node *nd=new Node(BB);
    nodes.push_back(nd);
    if(&*BB == ExitNode)
      exitNode=nd;
    if(&*BB==F.begin())
      startNode=nd;
  }

  // now do it againto insert edges
  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE; ++BB){
    Node *nd=findBB(nodes, BB);
    assert(nd && "No node for this edge!");

    for(BasicBlock::succ_iterator s=succ_begin(BB), se=succ_end(BB);
	s!=se; ++s){
      Node *nd2=findBB(nodes,*s);
      assert(nd2 && "No node for this edge!");
      Edge ed(nd,nd2,0);
      edges.push_back(ed);
    }
  }

  Graph g(nodes,edges, startNode, exitNode);

  //#ifdef DEBUG_PATH_PROFILES
  //std::cerr<<"Original graph\n";
  //printGraph(g);
  //#endif

  BasicBlock *fr = &F.front();

  // The graph is made acyclic: this is done
  // by removing back edges for now, and adding them later on
  vector<Edge> be;
  std::map<Node *, int> nodePriority; //it ranks nodes in depth first order traversal
  g.getBackEdges(be, nodePriority);
  /*
  std::cerr<<"Node priority--------------\n";
  for(std::map<Node *, int>::iterator MI = nodePriority.begin(),
        ME = nodePriority.end(); MI!=ME; ++MI)
    std::cerr<<MI->first->getElement()->getName()<<"->"<<MI->second<<"\n";
  std::cerr<<"End Node priority--------------\n";
  */
  //std::cerr<<"BackEdges-------------\n";
  //   for(vector<Edge>::iterator VI=be.begin(); VI!=be.end(); ++VI){
  //printEdge(*VI);
  //cerr<<"\n";
  //}
  //std::cerr<<"------\n";

#ifdef DEBUG_PATH_PROFILES
  cerr<<"Backedges:"<<be.size()<<endl;
#endif
  //Now we need to reflect the effect of back edges
  //This is done by adding dummy edges
  //If a->b is a back edge
  //Then we add 2 back edges for it:
  //1. from root->b (in vector stDummy)
  //and 2. from a->exit (in vector exDummy)
  vector<Edge> stDummy;
  vector<Edge> exDummy;
  addDummyEdges(stDummy, exDummy, g, be);

  //std::cerr<<"After adding dummy edges\n";
  //printGraph(g);

  // Now, every edge in the graph is assigned a weight
  // This weight later adds on to assign path
  // numbers to different paths in the graph
  //  All paths for now are acyclic,
  // since no back edges in the graph now
  // numPaths is the number of acyclic paths in the graph
  int numPaths=valueAssignmentToEdges(g, nodePriority);

  if(numPaths<=1 || numPaths >5000) return false;
  //std::cerr<<"Numpaths="<<numPaths<<std::endl;
  //printGraph(g);
  //create instruction allocation r and count
  //r is the variable that'll act like an accumulator
  //all along the path, we just add edge values to r
  //and at the end, r reflects the path number
  //count is an array: count[x] would store
  //the number of executions of path numbered x

  Instruction *rVar=new
    AllocaInst(PointerType::get(Type::IntTy),
               ConstantUInt::get(Type::UIntTy,1),"R");

  Instruction *countVar=new
    AllocaInst(PointerType::get(Type::IntTy),
               ConstantUInt::get(Type::UIntTy, numPaths), "Count");

  // insert initialization code in first (entry) BB
  // this includes initializing r and count
  insertInTopBB(&F.getEntryNode(),numPaths, rVar, countVar);

  //now process the graph: get path numbers,
  //get increments along different paths,
  //and assign "increments" and "updates" (to r and count)
  //"optimally". Finally, insert llvm code along various edges
  processGraph(g, rVar, countVar, be, stDummy, exDummy, numPaths, mn);

  return true;  // Always modifies function
}
<commit_msg>Incorporated changes in alloca instruction<commit_after>//===-- ProfilePaths.cpp - interface to insert instrumentation ---*- C++ -*--=//
//
// This inserts intrumentation for counting
// execution of paths though a given function
// Its implemented as a "Function" Pass, and called using opt
//
// This pass is implemented by using algorithms similar to
// 1."Efficient Path Profiling": Ball, T. and Larus, J. R.,
// Proceedings of Micro-29, Dec 1996, Paris, France.
// 2."Efficiently Counting Program events with support for on-line
//   "queries": Ball T., ACM Transactions on Programming Languages
//   and systems, Sep 1994.
//
// The algorithms work on a Graph constructed over the nodes
// made from Basic Blocks: The transformations then take place on
// the constucted graph (implementation in Graph.cpp and GraphAuxillary.cpp)
// and finally, appropriate instrumentation is placed over suitable edges.
// (code inserted through EdgeCode.cpp).
//
// The algorithm inserts code such that every acyclic path in the CFG
// of a function is identified through a unique number. the code insertion
// is optimal in the sense that its inserted over a minimal set of edges. Also,
// the algorithm makes sure than initialization, path increment and counter
// update can be collapsed into minimum number of edges.
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Support/CFG.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/Transforms/Instrumentation/Graph.h"
#include <iostream>
#include <fstream>

using std::vector;

struct ProfilePaths : public FunctionPass {
  bool runOnFunction(Function &F);

  // Before this pass, make sure that there is only one
  // entry and only one exit node for the function in the CFG of the function
  //
  void ProfilePaths::getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<UnifyFunctionExitNodes>();
  }
};

static RegisterOpt<ProfilePaths> X("paths", "Profile Paths");

// createProfilePathsPass - Create a new pass to add path profiling
//
Pass *createProfilePathsPass() {
  return new ProfilePaths();
}

static Node *findBB(std::vector<Node *> &st, BasicBlock *BB){
  for(std::vector<Node *>::iterator si=st.begin(); si!=st.end(); ++si){
    if(((*si)->getElement())==BB){
      return *si;
    }
  }
  return NULL;
}

//Per function pass for inserting counters and trigger code
bool ProfilePaths::runOnFunction(Function &F){

  static int mn = -1;

  if(F.isExternal()) {
    return false;
  }

  //increment counter for instrumented functions. mn is now function#
  mn++;

  // Transform the cfg s.t. we have just one exit node
  BasicBlock *ExitNode = getAnalysis<UnifyFunctionExitNodes>().getExitNode();

  //iterating over BBs and making graph
  std::vector<Node *> nodes;
  std::vector<Edge> edges;

  Node *tmp;
  Node *exitNode, *startNode;

  // The nodes must be uniquesly identified:
  // That is, no two nodes must hav same BB*

  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE; ++BB) {
    Node *nd=new Node(BB);
    nodes.push_back(nd);
    if(&*BB == ExitNode)
      exitNode=nd;
    if(&*BB==F.begin())
      startNode=nd;
  }

  // now do it againto insert edges
  for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE; ++BB){
    Node *nd=findBB(nodes, BB);
    assert(nd && "No node for this edge!");

    for(BasicBlock::succ_iterator s=succ_begin(BB), se=succ_end(BB);
	s!=se; ++s){
      Node *nd2=findBB(nodes,*s);
      assert(nd2 && "No node for this edge!");
      Edge ed(nd,nd2,0);
      edges.push_back(ed);
    }
  }

  Graph g(nodes,edges, startNode, exitNode);

#ifdef DEBUG_PATH_PROFILES
  std::cerr<<"Original graph\n";
  printGraph(g);
#endif

  BasicBlock *fr = &F.front();

  // The graph is made acyclic: this is done
  // by removing back edges for now, and adding them later on
  vector<Edge> be;
  std::map<Node *, int> nodePriority; //it ranks nodes in depth first order traversal
  g.getBackEdges(be, nodePriority);

#ifdef DEBUG_PATH_PROFILES
  std::cerr<<"BackEdges-------------\n";
  for(vector<Edge>::iterator VI=be.begin(); VI!=be.end(); ++VI){
    printEdge(*VI);
    cerr<<"\n";
  }
  std::cerr<<"------\n";
#endif

#ifdef DEBUG_PATH_PROFILES
  cerr<<"Backedges:"<<be.size()<<endl;
#endif
  //Now we need to reflect the effect of back edges
  //This is done by adding dummy edges
  //If a->b is a back edge
  //Then we add 2 back edges for it:
  //1. from root->b (in vector stDummy)
  //and 2. from a->exit (in vector exDummy)
  vector<Edge> stDummy;
  vector<Edge> exDummy;
  addDummyEdges(stDummy, exDummy, g, be);

#ifdef DEBUG_PATH_PROFILES
  std::cerr<<"After adding dummy edges\n";
  printGraph(g);
#endif

  // Now, every edge in the graph is assigned a weight
  // This weight later adds on to assign path
  // numbers to different paths in the graph
  //  All paths for now are acyclic,
  // since no back edges in the graph now
  // numPaths is the number of acyclic paths in the graph
  int numPaths=valueAssignmentToEdges(g, nodePriority, be);

  if(numPaths<=1 || numPaths >5000) return false;

#ifdef DEBUG_PATH_PROFILES
  printGraph(g);
#endif

  //create instruction allocation r and count
  //r is the variable that'll act like an accumulator
  //all along the path, we just add edge values to r
  //and at the end, r reflects the path number
  //count is an array: count[x] would store
  //the number of executions of path numbered x

  Instruction *rVar=new
    AllocaInst(Type::IntTy,
               ConstantUInt::get(Type::UIntTy,1),"R");

  Instruction *countVar=new
    AllocaInst(Type::IntTy,
               ConstantUInt::get(Type::UIntTy, numPaths), "Count");

  // insert initialization code in first (entry) BB
  // this includes initializing r and count
  insertInTopBB(&F.getEntryNode(),numPaths, rVar, countVar);

  //now process the graph: get path numbers,
  //get increments along different paths,
  //and assign "increments" and "updates" (to r and count)
  //"optimally". Finally, insert llvm code along various edges
  processGraph(g, rVar, countVar, be, stDummy, exDummy, numPaths, mn);

  return true;  // Always modifies function
}
<|endoftext|>


<commit_before>#include "group_table.h"
#include "metric_table.h"
#include "tables.h"
#include "dictionary.h"
#include <monsoon/history/dir/hdir_exception.h>
#include <algorithm>

namespace monsoon::history::v2 {

group_table::~group_table() noexcept {}

auto group_table::get_dictionary()
-> std::shared_ptr<dictionary> {
  return parent().get_dictionary();
}

auto group_table::get_dictionary() const
-> std::shared_ptr<const dictionary> {
  return parent().get_dictionary();
}

auto group_table::get_ctx() const
-> const encdec_ctx& {
  return parent().get_ctx();
}

auto group_table::from_xdr(
    std::shared_ptr<tables> parent,
    xdr::xdr_istream& in)
-> std::shared_ptr<group_table> {
  auto tbl = std::make_shared<group_table>(parent);
  tbl->decode(in);
  return tbl;
}

auto group_table::decode(xdr::xdr_istream& in)
-> void {
  presence_.decode(in);

  data_.clear();
  in.get_collection(
      [](xdr::xdr_istream& in) {
        std::uint32_t metric_name_ref = in.get_uint32();
        file_segment_ptr ptr = file_segment_ptr::from_xdr(in);
        return std::make_pair(metric_name_ref, ptr);
      },
      data_);

  std::sort(data_.begin(), data_.end(),
      [](const auto& x, const auto& y) noexcept {
        return x.first < y.first;
      });
  data_.erase(
      std::unique(data_.begin(), data_.end(),
          [](const auto& x, const auto& y) noexcept {
            return x.first == y.first;
          }),
      data_.end());
}

auto group_table::read_(data_type::const_reference ptr) const
-> std::shared_ptr<const metric_table> {
  auto xdr = get_ctx().new_reader(ptr.second, metric_table::is_compressed);
  auto result = metric_table::from_xdr(std::const_pointer_cast<group_table>(shared_from_this()), xdr);
  if (!xdr.at_end()) throw dirhistory_exception("xdr data remaining");
  xdr.close();
  return result;
}

} /* namespace monsoon::history::v2 */
<commit_msg>Use cache for metric_table decoding.<commit_after>#include "group_table.h"
#include "metric_table.h"
#include "tables.h"
#include "dictionary.h"
#include <monsoon/history/dir/hdir_exception.h>
#include <algorithm>

namespace monsoon::history::v2 {

group_table::~group_table() noexcept {}

auto group_table::get_dictionary()
-> std::shared_ptr<dictionary> {
  return parent().get_dictionary();
}

auto group_table::get_dictionary() const
-> std::shared_ptr<const dictionary> {
  return parent().get_dictionary();
}

auto group_table::get_ctx() const
-> const encdec_ctx& {
  return parent().get_ctx();
}

auto group_table::from_xdr(
    std::shared_ptr<tables> parent,
    xdr::xdr_istream& in)
-> std::shared_ptr<group_table> {
  auto tbl = std::make_shared<group_table>(parent);
  tbl->decode(in);
  return tbl;
}

auto group_table::decode(xdr::xdr_istream& in)
-> void {
  presence_.decode(in);

  data_.clear();
  in.get_collection(
      [](xdr::xdr_istream& in) {
        std::uint32_t metric_name_ref = in.get_uint32();
        file_segment_ptr ptr = file_segment_ptr::from_xdr(in);
        return std::make_pair(metric_name_ref, ptr);
      },
      data_);

  std::sort(data_.begin(), data_.end(),
      [](const auto& x, const auto& y) noexcept {
        return x.first < y.first;
      });
  data_.erase(
      std::unique(data_.begin(), data_.end(),
          [](const auto& x, const auto& y) noexcept {
            return x.first == y.first;
          }),
      data_.end());
}

auto group_table::read_(data_type::const_reference ptr) const
-> std::shared_ptr<const metric_table> {
  return get_dynamics_cache<metric_table>(std::const_pointer_cast<group_table>(shared_from_this()), ptr.second);
}

} /* namespace monsoon::history::v2 */
<|endoftext|>


<commit_before>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

#ifndef BulletSiconosFwd_hpp
#define BulletSiconosFwd_hpp

#include "SiconosPointers.hpp"

DEFINE_SPTR(btCollisionShape);
DEFINE_SPTR(btBoxShape);
DEFINE_SPTR(btCylinderShape);
DEFINE_SPTR(btManifoldPoint);

DEFINE_SPTR(btTriangleIndexVertexMaterialArray);

DEFINE_SPTR(btCollisionObject);
DEFINE_SAPTR(btCollisionObject);

DEFINE_SPTR(btCollisionWorld);
DEFINE_SPTR(btDefaultCollisionConfiguration);
DEFINE_SPTR(btCollisionDispatcher);
DEFINE_SPTR(btVector3);
DEFINE_SPTR(btQuaternion);

DEFINE_SPTR(btPersistentManifold);

DEFINE_SPTR(btBroadphaseInterface);

//DEFINE_SPTR(BulletDS);
DEFINE_SPTR(BulletWeightedShape);
//DEFINE_SPTR(BulletR);
//DEFINE_SPTR(BulletFrom1DLocalFrameR);
//DEFINE_SPTR(BulletSpaceFilter);
//DEFINE_SPTR(BulletTimeStepping);
DEFINE_SPTR(CollisionObjects);
DEFINE_SPTR(StaticObjects);

#include "MechanicsFwd.hpp"

#endif
<commit_msg>[mechanics] silent a warning for a struct redeclared as a class<commit_after>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

#ifndef BulletSiconosFwd_hpp
#define BulletSiconosFwd_hpp

#include "SiconosPointers.hpp"

DEFINE_SPTR(btCollisionShape);
DEFINE_SPTR(btBoxShape);
DEFINE_SPTR(btCylinderShape);
DEFINE_SPTR(btManifoldPoint);

DEFINE_SPTR(btTriangleIndexVertexMaterialArray);

DEFINE_SPTR(btCollisionObject);
DEFINE_SAPTR(btCollisionObject);

DEFINE_SPTR(btCollisionWorld);
DEFINE_SPTR(btDefaultCollisionConfiguration);
DEFINE_SPTR(btCollisionDispatcher);
DEFINE_SPTR(btVector3);
DEFINE_SPTR(btQuaternion);

DEFINE_SPTR(btPersistentManifold);

DEFINE_SPTR(btBroadphaseInterface);

//DEFINE_SPTR(BulletDS);
DEFINE_SPTR(BulletWeightedShape);
//DEFINE_SPTR(BulletR);
//DEFINE_SPTR(BulletFrom1DLocalFrameR);
//DEFINE_SPTR(BulletSpaceFilter);
//DEFINE_SPTR(BulletTimeStepping);
DEFINE_SPTR(CollisionObjects);
DEFINE_SPTR_STRUCT(StaticObjects);

#include "MechanicsFwd.hpp"

#endif
<|endoftext|>


<commit_before>#include "Stdafx.h"
#include "SceneTextRegionExtractor.h"

using namespace std;
using namespace cv;

namespace ImageQuality
{
	IList<Region^>^ SceneTextRegionExtractor::SimpleWatermark(array<byte>^ buffer)
	{
		Mat img = ReadImage(buffer);
		List<Region^>^ list = gcnew List<Region^>(5);

		IList<Region^>^ red = DetectAndRotate(img, Scalar(0, 0, 200), Scalar(50, 50, 255));
		list->AddRange(red);

		IList<Region^>^ yellow = DetectAndRotate(img, Scalar(0, 225, 225), Scalar(50, 255, 255));
		list->AddRange(yellow);

		IList<Region^>^ black = DetectAndRotate(img, Scalar(0, 0, 0), Scalar(25, 25, 25));
		list->AddRange(black);

		IList<Region^>^ white = DetectAndRotate(img, Scalar(200, 200, 200), Scalar(255, 255, 255));
		list->AddRange(white);

		return list;
	}

	IList<Region^>^ SceneTextRegionExtractor::DetectAndRotate(Mat img, Scalar lower, Scalar upper)
	{
		Mat output;
		inRange(img, lower, upper, output);

		Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(2, 2));
		morphologyEx(output, output, MORPH_CLOSE, morphKernel);

		Mat contourImg = output.clone();

		vector<vector<Point>> contours;
		vector<Vec4i> hierarchy;
		findContours(contourImg, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

		if (!hierarchy.empty())
		{
			vector<float> angles;
			for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
			{
				RotatedRect box = minAreaRect(contours[idx]);

				float area = box.size.area();
				if (box.size.width > MinWidth && box.size.height > MinHeight)
				{
					float angle = box.angle;
					if (angle < -45)
						angle += 90;
					angles.push_back(angle);
				}
			}

			if (!angles.empty())
			{
				Nullable<float> bestAngle = FindBestAngle(angles);
				if (bestAngle.HasValue)
				{
					float angle = (bestAngle.Value > -18 && bestAngle.Value < 18) ? 0 : bestAngle.Value;

					int len = max(output.cols, output.rows);
					Point2f pt(len / 2., len / 2.);
					Mat r = getRotationMatrix2D(pt, angle, 1);
					warpAffine(output, output, r, Size(len, len));

					cvtColor(output, output, CV_GRAY2BGR);

					array<byte>^ b = ToByteArray(output, ".tiff");
					return GetRegions(b);
				}
			}
		}

		return gcnew List<Region^>(0);
	}

	IList<Region^>^ SceneTextRegionExtractor::GetRegions(array<byte>^ buffer)
	{
		List<Region^>^ list = gcnew List<Region^>(5);
		Mat image = ReadImage(buffer);

		Mat tiff;
		cvtColor(image, tiff, CV_BGR2GRAY);
		threshold(tiff, tiff, 0, 255, THRESH_BINARY | THRESH_OTSU);

		Mat gray;
		cvtColor(image, gray, CV_BGR2GRAY);

		Mat scaled = gray;
		pyrDown(scaled, scaled);
		pyrUp(scaled, scaled);

		Mat grad;
		Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
		morphologyEx(scaled, grad, MORPH_GRADIENT, morphKernel);

		Mat bw;
		threshold(grad, bw, 32, 255, THRESH_BINARY | THRESH_OTSU);

		Mat connected;
		morphKernel = getStructuringElement(MORPH_RECT, Size(8, 1));
		morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);

		Mat mask = Mat::zeros(bw.size(), CV_8UC1);
		vector<vector<Point>> contours;
		vector<Vec4i> hierarchy;
		findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

		if (!hierarchy.empty())
		{
			vector<Rect> regionRects;
			for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
			{
				Rect rect = boundingRect(contours[idx]);
				if (rect.height > 400)
					continue;

				Mat maskROI(mask, rect);
				maskROI = Scalar(0, 0, 0);

				drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
				double r = (double)countNonZero(maskROI) / (rect.width*rect.height);

				if (r > .45 && rect.width >= 10 && rect.height >= 12)
				{
					regionRects.push_back(rect);
				}
			}

			if (!regionRects.empty())
			{
				Mat rectMask(Size(gray.cols, gray.rows), gray.type(), Scalar(0, 0, 0));
				for each (Rect rect in regionRects)
				{
					Rect expanded(rect.x - 10, rect.y, rect.width + 20, rect.height);
					rectangle(rectMask, expanded, Scalar(255, 255, 255), 2);
				}

				findContours(rectMask, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				vector<Rect> mergedRects;
				for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
				{
					Rect rect = boundingRect(contours[idx]);
					Rect tighter(rect.x + 10, rect.y - 1, rect.width - 20, rect.height + 2);
					if (tighter.width >= MinWidth && tighter.height >= MinHeight)
					{
						mergedRects.push_back(tighter);
					}
				}

				if (!mergedRects.empty())
				{
					for each (Rect rect in mergedRects)
					{
						Mat roi(tiff, rect);
						Mat local = roi.clone();

						if (HeuristicEvaluation(local))
						{
							rectangle(image, rect, Scalar(0, 255, 0), 2);

							//imshow("roi", roi);
							//waitKey(0);

							Region^ region = gcnew Region(rect, ToByteArray(local, ".tiff"));
							list->Add(region);
						}
						else
						{
							rectangle(image, rect, Scalar(0, 0, 255), 2);
						}
					}
				}
			}
		}

		//imshow("debug", image);
		//waitKey(0);

		return list;
	}

	bool SceneTextRegionExtractor::HeuristicEvaluation(Mat roi)
	{
		double totC = countNonZero(roi) / (double)(roi.cols * roi.rows);
		if (totC < 0.5)
		{
			bitwise_not(roi, roi);
		}

		vector<double> horVals;
		for (int x = 0; x < roi.rows; x++)
		{
			Mat row = roi.row(x);
			double c = (roi.cols - countNonZero(row)) / (double)roi.cols;
			horVals.push_back(c);
		}

		if (horVals.empty() || horVals[0] != 0 || horVals[horVals.size() - 1] != 0)
		{
			return false;
		}

		vector<double> verVals;
		for (int x = 0; x < roi.cols; x++)
		{
			Mat col = roi.col(x);
			double c = (roi.rows - countNonZero(col)) / (double)roi.rows;
			verVals.push_back(c);
		}

		vector<vector<double>> vertDivided = HeuristicSplit(verVals);

		if (vertDivided.empty() || vertDivided.size() < 2) //Text has spaces between chars
		{
			return false;
		}

		/*Mat vertMask = Mat(Size(verVals.size(), 100), CV_8UC1, Scalar(255));
		for (int i = 0; i < verVals.size(); i++)
		{
			int x = (int)(verVals[i] * 100);
			for (int j = 0; j < x; j++)
			{
				vertMask.at<uchar>(Point(i, 99 - j)) = 0;
			}
		}

		Mat horMask = Mat(Size(100, horVals.size()), CV_8UC1, Scalar(255));
		for (int i = 0; i < horVals.size(); i++)
		{
			int x = (int)(horVals[i] * 100);
			for (int j = 0; j < x; j++)
			{
				horMask.at<uchar>(Point(j, i)) = 0;
			}
		}

		imshow("roi", roi);
		imshow("vertical_mask", vertMask);
		imshow("horizontal_mask", horMask);
		waitKey(0);*/

		return true;
	}

	vector<vector<double>> SceneTextRegionExtractor::HeuristicSplit(vector<double> values)
	{
		vector<vector<double>> divided;
		vector<double> current;
		for (int i = 0; i < values.size(); i++)
		{
			if (values[i] == 0)
			{
				if (!current.empty())
				{
					divided.push_back(current);
					current.clear();
				}
			}
			else
			{
				current.push_back(values[i]);
			}
		}
		return divided;
	}

	Nullable<float> SceneTextRegionExtractor::FindBestAngle(vector<float> angles)
	{
		float bestAngle;
		int bestAngleCount = 1;
		bool found = false;

		if (!angles.empty())
		{
			for (int i = 0; i < angles.size() - 1; i++)
			{
				float angle = angles[i];
				int count = 1;
				for (int j = i + 1; j < angles.size(); j++)
				{
					if (i == j) continue;

					if (abs(angles[i] - angles[j]) < 10)
					{
						if (std::abs(angles[j]) < std::abs(angles[i]))
						{
							angle = angles[j];
						}
						count++;
					}
				}

				if (count > bestAngleCount && count >= angles.size() * 0.6)
				{
					bestAngle = angle;
					bestAngleCount = count;
					found = true;
				}
			}
		}
		return found ? bestAngle : Nullable<float>();
	}

	Mat SceneTextRegionExtractor::ReadImage(array<byte>^ buffer)
	{
		pin_ptr<byte> px = &buffer[0];
		Mat datax(1, buffer->Length, CV_8U, (void*)px, CV_AUTO_STEP);
		return imdecode(datax, CV_LOAD_IMAGE_COLOR);
	}

	array<byte>^ SceneTextRegionExtractor::ToByteArray(Mat image, const std::string& extension)
	{
		vector<byte> buffer;
		imencode(extension, image, buffer);

		array<byte>^ bytes = gcnew array<byte>(buffer.size());

		UnmanagedMemoryStream^ sourceStream = gcnew UnmanagedMemoryStream(buffer.data(), buffer.size());
		sourceStream->Read(bytes, 0, buffer.size());

		return bytes;
	}

	void SceneTextRegionExtractor::WriteToStream(const std::string& extension, Mat image, Stream^ stream)
	{
		vector<byte> buffer;
		imencode(extension, image, buffer);

		UnmanagedMemoryStream^ sourceStream = gcnew UnmanagedMemoryStream(buffer.data(), buffer.size());
		sourceStream->CopyTo(stream);
	}
}<commit_msg>Heuristic tweak<commit_after>#include "Stdafx.h"
#include "SceneTextRegionExtractor.h"

using namespace std;
using namespace cv;

namespace ImageQuality
{
	IList<Region^>^ SceneTextRegionExtractor::SimpleWatermark(array<byte>^ buffer)
	{
		Mat img = ReadImage(buffer);
		List<Region^>^ list = gcnew List<Region^>(5);

		IList<Region^>^ red = DetectAndRotate(img, Scalar(0, 0, 200), Scalar(50, 50, 255));
		list->AddRange(red);

		IList<Region^>^ yellow = DetectAndRotate(img, Scalar(0, 225, 225), Scalar(50, 255, 255));
		list->AddRange(yellow);

		IList<Region^>^ black = DetectAndRotate(img, Scalar(0, 0, 0), Scalar(25, 25, 25));
		list->AddRange(black);

		IList<Region^>^ white = DetectAndRotate(img, Scalar(200, 200, 200), Scalar(255, 255, 255));
		list->AddRange(white);

		return list;
	}

	IList<Region^>^ SceneTextRegionExtractor::DetectAndRotate(Mat img, Scalar lower, Scalar upper)
	{
		Mat output;
		inRange(img, lower, upper, output);

		Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(2, 2));
		morphologyEx(output, output, MORPH_CLOSE, morphKernel);

		Mat contourImg = output.clone();

		vector<vector<Point>> contours;
		vector<Vec4i> hierarchy;
		findContours(contourImg, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

		if (!hierarchy.empty())
		{
			vector<float> angles;
			for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
			{
				RotatedRect box = minAreaRect(contours[idx]);

				float area = box.size.area();
				if (box.size.width > MinWidth && box.size.height > MinHeight)
				{
					float angle = box.angle;
					if (angle < -45)
						angle += 90;
					angles.push_back(angle);
				}
			}

			if (!angles.empty())
			{
				Nullable<float> bestAngle = FindBestAngle(angles);
				if (bestAngle.HasValue)
				{
					float angle = (bestAngle.Value > -18 && bestAngle.Value < 18) ? 0 : bestAngle.Value;

					int len = max(output.cols, output.rows);
					Point2f pt(len / 2., len / 2.);
					Mat r = getRotationMatrix2D(pt, angle, 1);
					warpAffine(output, output, r, Size(len, len));

					cvtColor(output, output, CV_GRAY2BGR);

					array<byte>^ b = ToByteArray(output, ".tiff");
					return GetRegions(b);
				}
			}
		}

		return gcnew List<Region^>(0);
	}

	IList<Region^>^ SceneTextRegionExtractor::GetRegions(array<byte>^ buffer)
	{
		List<Region^>^ list = gcnew List<Region^>(5);
		Mat image = ReadImage(buffer);

		Mat tiff;
		cvtColor(image, tiff, CV_BGR2GRAY);
		threshold(tiff, tiff, 0, 255, THRESH_BINARY | THRESH_OTSU);

		Mat gray;
		cvtColor(image, gray, CV_BGR2GRAY);

		Mat scaled = gray;
		pyrDown(scaled, scaled);
		pyrUp(scaled, scaled);

		Mat grad;
		Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
		morphologyEx(scaled, grad, MORPH_GRADIENT, morphKernel);

		Mat bw;
		threshold(grad, bw, 32, 255, THRESH_BINARY | THRESH_OTSU);

		Mat connected;
		morphKernel = getStructuringElement(MORPH_RECT, Size(8, 1));
		morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);

		Mat mask = Mat::zeros(bw.size(), CV_8UC1);
		vector<vector<Point>> contours;
		vector<Vec4i> hierarchy;
		findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

		if (!hierarchy.empty())
		{
			vector<Rect> regionRects;
			for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
			{
				Rect rect = boundingRect(contours[idx]);
				if (rect.height > 400)
					continue;

				Mat maskROI(mask, rect);
				maskROI = Scalar(0, 0, 0);

				drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
				double r = (double)countNonZero(maskROI) / (rect.width*rect.height);

				if (r > .45 && rect.width >= 10 && rect.height >= 12)
				{
					regionRects.push_back(rect);
				}
			}

			if (!regionRects.empty())
			{
				Mat rectMask(Size(gray.cols, gray.rows), gray.type(), Scalar(0, 0, 0));
				for each (Rect rect in regionRects)
				{
					Rect expanded(rect.x - 10, rect.y, rect.width + 20, rect.height);
					rectangle(rectMask, expanded, Scalar(255, 255, 255), 2);
				}

				findContours(rectMask, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				vector<Rect> mergedRects;
				for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
				{
					Rect rect = boundingRect(contours[idx]);
					Rect tighter(rect.x + 10, rect.y - 1, rect.width - 20, rect.height + 2);
					if (tighter.width >= MinWidth && tighter.height >= MinHeight)
					{
						mergedRects.push_back(tighter);
					}
				}

				if (!mergedRects.empty())
				{
					for each (Rect rect in mergedRects)
					{
						Mat roi(tiff, rect);
						Mat local = roi.clone();

						if (HeuristicEvaluation(local))
						{
							rectangle(image, rect, Scalar(0, 255, 0), 2);

							//imshow("roi", roi);
							//waitKey(0);

							Region^ region = gcnew Region(rect, ToByteArray(local, ".tiff"));
							list->Add(region);
						}
						else
						{
							rectangle(image, rect, Scalar(0, 0, 255), 2);
						}
					}
				}
			}
		}

		//imshow("debug", image);
		//waitKey(0);

		return list;
	}

	bool SceneTextRegionExtractor::HeuristicEvaluation(Mat roi)
	{
		double totC = countNonZero(roi) / (double)(roi.cols * roi.rows);
		if (totC < 0.4)
		{
			bitwise_not(roi, roi);
		}

		vector<double> horVals;
		for (int x = 0; x < roi.rows; x++)
		{
			Mat row = roi.row(x);
			double c = (roi.cols - countNonZero(row)) / (double)roi.cols;
			horVals.push_back(c);
		}

		if (horVals.empty() || horVals[0] != 0 || horVals[horVals.size() - 1] != 0)
		{
			/*Mat horMask = Mat(Size(100, horVals.size()), CV_8UC1, Scalar(255));
			for (int i = 0; i < horVals.size(); i++)
			{
				int x = (int)(horVals[i] * 100);
				for (int j = 0; j < x; j++)
				{
					horMask.at<uchar>(Point(j, i)) = 0;
				}
			}

			imshow("roi", roi);
			imshow("horizontal_mask", horMask);
			waitKey(0);*/

			return false;
		}

		vector<double> verVals;
		for (int x = 0; x < roi.cols; x++)
		{
			Mat col = roi.col(x);
			double c = (roi.rows - countNonZero(col)) / (double)roi.rows;
			verVals.push_back(c);
		}

		vector<vector<double>> vertDivided = HeuristicSplit(verVals);

		if (vertDivided.empty() || vertDivided.size() < 2) //Text has spaces between chars
		{
			/*Mat vertMask = Mat(Size(verVals.size(), 100), CV_8UC1, Scalar(255));
			for (int i = 0; i < verVals.size(); i++)
			{
				int x = (int)(verVals[i] * 100);
				for (int j = 0; j < x; j++)
				{
					vertMask.at<uchar>(Point(i, 99 - j)) = 0;
				}
			}

			imshow("roi", roi);
			imshow("vertical_mask", vertMask);
			waitKey(0);*/

			return false;
		}

		return true;
	}

	vector<vector<double>> SceneTextRegionExtractor::HeuristicSplit(vector<double> values)
	{
		vector<vector<double>> divided;
		vector<double> current;
		for (int i = 0; i < values.size(); i++)
		{
			if (values[i] == 0)
			{
				if (!current.empty())
				{
					divided.push_back(current);
					current.clear();
				}
			}
			else
			{
				current.push_back(values[i]);
			}
		}
		return divided;
	}

	Nullable<float> SceneTextRegionExtractor::FindBestAngle(vector<float> angles)
	{
		float bestAngle;
		int bestAngleCount = 1;
		bool found = false;

		if (!angles.empty())
		{
			for (int i = 0; i < angles.size() - 1; i++)
			{
				float angle = angles[i];
				int count = 1;
				for (int j = i + 1; j < angles.size(); j++)
				{
					if (i == j) continue;

					if (abs(angles[i] - angles[j]) < 10)
					{
						if (std::abs(angles[j]) < std::abs(angles[i]))
						{
							angle = angles[j];
						}
						count++;
					}
				}

				if (count > bestAngleCount && count >= angles.size() * 0.6)
				{
					bestAngle = angle;
					bestAngleCount = count;
					found = true;
				}
			}
		}
		return found ? bestAngle : Nullable<float>();
	}

	Mat SceneTextRegionExtractor::ReadImage(array<byte>^ buffer)
	{
		pin_ptr<byte> px = &buffer[0];
		Mat datax(1, buffer->Length, CV_8U, (void*)px, CV_AUTO_STEP);
		return imdecode(datax, CV_LOAD_IMAGE_COLOR);
	}

	array<byte>^ SceneTextRegionExtractor::ToByteArray(Mat image, const std::string& extension)
	{
		vector<byte> buffer;
		imencode(extension, image, buffer);

		array<byte>^ bytes = gcnew array<byte>(buffer.size());

		UnmanagedMemoryStream^ sourceStream = gcnew UnmanagedMemoryStream(buffer.data(), buffer.size());
		sourceStream->Read(bytes, 0, buffer.size());

		return bytes;
	}

	void SceneTextRegionExtractor::WriteToStream(const std::string& extension, Mat image, Stream^ stream)
	{
		vector<byte> buffer;
		imencode(extension, image, buffer);

		UnmanagedMemoryStream^ sourceStream = gcnew UnmanagedMemoryStream(buffer.data(), buffer.size());
		sourceStream->CopyTo(stream);
	}
}<|endoftext|>


<commit_before>/* Copyright 2019 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file IndexTreeGenerator.cpp
 *
 *  @author Kristofer Björnson
 */

#include "TBTK/PropertyExtractor/IndexTreeGenerator.h"
#include "TBTK/TBTKMacros.h"

using namespace std;

namespace TBTK{
namespace PropertyExtractor{

IndexTreeGenerator::IndexTreeGenerator(const Model &model) : model(model){
	keepSummationWildcards = false;
	keepSpinWildcards = false;
}

IndexTree IndexTreeGenerator::generate(const vector<Index> &patterns) const{
	IndexTree indexTree;
	const HoppingAmplitudeSet &hoppingAmplitudeSet
		= model.getHoppingAmplitudeSet();

	for(unsigned int n = 0; n < patterns.size(); n++){
		Index pattern = *(patterns.begin() + n);

		vector<Index> components = pattern.split();

		if(components.size() == 1){
			pattern = components[0];

			for(unsigned int c = 0; c < pattern.getSize(); c++){
				switch(pattern.at(c)){
				case IDX_ALL:
				case IDX_SUM_ALL:
				case IDX_SPIN:
					pattern.at(c) = IDX_ALL;
					break;
				default:
					TBTKAssert(
						pattern.at(c) >= 0,
						"PropertyExtractor::generateIndexTree()",
						"Subindex " << c << " of pattern " << n << " is invalid.",
						"Must be non-negative, IDX_ALL, IDX_SUM_ALL, or IDX_SPIN."
					);
					break;
				}
				if(pattern.at(c) < 0)
					pattern.at(c) = IDX_ALL;
			}

			vector<Index> indices = hoppingAmplitudeSet.getIndexList(
				pattern
			);
			Index p = *(patterns.begin() + n);
			for(unsigned int c = 0; c < indices.size(); c++){
				for(unsigned int m = 0; m < p.getSize(); m++){
					if(
						keepSummationWildcards
						&& p.at(m).isSummationIndex()
					){
						indices.at(c).at(m) = IDX_SUM_ALL;
					}
					if(
						keepSpinWildcards
						&& p.at(m).isSpinIndex()
					){
						indices.at(c).at(m) = IDX_SPIN;
					}
				}
			}
			for(unsigned int c = 0; c < indices.size(); c++)
				indexTree.add(indices.at(c));

			break;
		}
		else if(components.size() != 0){
			IndexTree firstIndexTree = generate({components[0]});
			Index remainingIndices;
			for(unsigned int n = 1; n < components.size(); n++){
				if(n != 1){
					remainingIndices.pushBack(
						IDX_SEPARATOR
					);
				}
				for(
					unsigned int c = 0;
					c < components[n].getSize();
					c++
				){
					remainingIndices.pushBack(components[n][c]);
				}
			}
			IndexTree remainingIndexTree = generate({remainingIndices});
			for(
				IndexTree::ConstIterator iterator0
					= firstIndexTree.cbegin();
				iterator0 != firstIndexTree.cend();
				++iterator0
			){
				for(
					IndexTree::ConstIterator iterator1
						= remainingIndexTree.cbegin();
					iterator1 != remainingIndexTree.cend();
					++iterator1
				){
					indexTree.add({*iterator0, *iterator1});
				}
			}

			break;
		}
		else{
			TBTKExit(
				"PropertyExtractor::IndexTreeGenerator::generate()",
				"Invalid pattern '" << pattern << "'.",
				""
			);
		}
	}

	indexTree.generateLinearMap();

	return indexTree;
}

};	//End of namesapce PropertyExtractor
};	//End of namespace TBTK
<commit_msg>Updated error message.<commit_after>/* Copyright 2019 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file IndexTreeGenerator.cpp
 *
 *  @author Kristofer Björnson
 */

#include "TBTK/PropertyExtractor/IndexTreeGenerator.h"
#include "TBTK/TBTKMacros.h"

using namespace std;

namespace TBTK{
namespace PropertyExtractor{

IndexTreeGenerator::IndexTreeGenerator(const Model &model) : model(model){
	keepSummationWildcards = false;
	keepSpinWildcards = false;
}

IndexTree IndexTreeGenerator::generate(const vector<Index> &patterns) const{
	IndexTree indexTree;
	const HoppingAmplitudeSet &hoppingAmplitudeSet
		= model.getHoppingAmplitudeSet();

	for(unsigned int n = 0; n < patterns.size(); n++){
		Index pattern = *(patterns.begin() + n);

		vector<Index> components = pattern.split();

		if(components.size() == 1){
			pattern = components[0];

			for(unsigned int c = 0; c < pattern.getSize(); c++){
				switch(pattern.at(c)){
				case IDX_ALL:
				case IDX_SUM_ALL:
				case IDX_SPIN:
					pattern.at(c) = IDX_ALL;
					break;
				default:
					TBTKAssert(
						pattern.at(c) >= 0,
						"PropertyExtractor::IndexTreeGenerator()",
						"Subindex " << c << " of pattern " << n << " is invalid.",
						"Must be non-negative, IDX_ALL, IDX_SUM_ALL, or IDX_SPIN."
					);
					break;
				}
				if(pattern.at(c) < 0)
					pattern.at(c) = IDX_ALL;
			}

			vector<Index> indices = hoppingAmplitudeSet.getIndexList(
				pattern
			);
			Index p = *(patterns.begin() + n);
			for(unsigned int c = 0; c < indices.size(); c++){
				for(unsigned int m = 0; m < p.getSize(); m++){
					if(
						keepSummationWildcards
						&& p.at(m).isSummationIndex()
					){
						indices.at(c).at(m) = IDX_SUM_ALL;
					}
					if(
						keepSpinWildcards
						&& p.at(m).isSpinIndex()
					){
						indices.at(c).at(m) = IDX_SPIN;
					}
				}
			}
			for(unsigned int c = 0; c < indices.size(); c++)
				indexTree.add(indices.at(c));

			break;
		}
		else if(components.size() != 0){
			IndexTree firstIndexTree = generate({components[0]});
			Index remainingIndices;
			for(unsigned int n = 1; n < components.size(); n++){
				if(n != 1){
					remainingIndices.pushBack(
						IDX_SEPARATOR
					);
				}
				for(
					unsigned int c = 0;
					c < components[n].getSize();
					c++
				){
					remainingIndices.pushBack(components[n][c]);
				}
			}
			IndexTree remainingIndexTree = generate({remainingIndices});
			for(
				IndexTree::ConstIterator iterator0
					= firstIndexTree.cbegin();
				iterator0 != firstIndexTree.cend();
				++iterator0
			){
				for(
					IndexTree::ConstIterator iterator1
						= remainingIndexTree.cbegin();
					iterator1 != remainingIndexTree.cend();
					++iterator1
				){
					indexTree.add({*iterator0, *iterator1});
				}
			}

			break;
		}
		else{
			TBTKExit(
				"PropertyExtractor::IndexTreeGenerator::generate()",
				"Invalid pattern '" << pattern << "'.",
				""
			);
		}
	}

	indexTree.generateLinearMap();

	return indexTree;
}

};	//End of namesapce PropertyExtractor
};	//End of namespace TBTK
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/html/canvas/ANGLEInstancedArrays.h"

#include "core/html/canvas/WebGLRenderingContext.h"
#include "core/platform/graphics/Extensions3D.h"

namespace WebCore {

ANGLEInstancedArrays::ANGLEInstancedArrays(WebGLRenderingContext* context)
    : WebGLExtension(context)
{
    ScriptWrappable::init(this);
    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
}

ANGLEInstancedArrays::~ANGLEInstancedArrays()
{
}

WebGLExtension::ExtensionName ANGLEInstancedArrays::getName() const
{
    return ANGLEInstancedArraysName;
}

PassRefPtr<ANGLEInstancedArrays> ANGLEInstancedArrays::create(WebGLRenderingContext* context)
{
    return adoptRef(new ANGLEInstancedArrays(context));
}

bool ANGLEInstancedArrays::supported(WebGLRenderingContext* context)
{
    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
    return extensions->supports("GL_ANGLE_instanced_arrays");
}

const char* ANGLEInstancedArrays::getExtensionName()
{
    return "ANGLE_instanced_arrays";
}

void ANGLEInstancedArrays::drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
{
    m_context->drawArraysInstancedANGLE(mode, first, count, primcount);
}

void ANGLEInstancedArrays::drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
{
    m_context->drawElementsInstancedANGLE(mode, count, type, offset, primcount);
}

void ANGLEInstancedArrays::vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor)
{
    m_context->vertexAttribDivisorANGLE(index, divisor);
}

} // namespace WebCore
<commit_msg>Fixed lost context handling in ANGLE_instanced_arrays<commit_after>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/html/canvas/ANGLEInstancedArrays.h"

#include "core/html/canvas/WebGLRenderingContext.h"
#include "core/platform/graphics/Extensions3D.h"

namespace WebCore {

ANGLEInstancedArrays::ANGLEInstancedArrays(WebGLRenderingContext* context)
    : WebGLExtension(context)
{
    ScriptWrappable::init(this);
    context->graphicsContext3D()->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
}

ANGLEInstancedArrays::~ANGLEInstancedArrays()
{
}

WebGLExtension::ExtensionName ANGLEInstancedArrays::getName() const
{
    return ANGLEInstancedArraysName;
}

PassRefPtr<ANGLEInstancedArrays> ANGLEInstancedArrays::create(WebGLRenderingContext* context)
{
    return adoptRef(new ANGLEInstancedArrays(context));
}

bool ANGLEInstancedArrays::supported(WebGLRenderingContext* context)
{
    Extensions3D* extensions = context->graphicsContext3D()->getExtensions();
    return extensions->supports("GL_ANGLE_instanced_arrays");
}

const char* ANGLEInstancedArrays::getExtensionName()
{
    return "ANGLE_instanced_arrays";
}

void ANGLEInstancedArrays::drawArraysInstancedANGLE(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
{
    if (isLost())
        return;

    m_context->drawArraysInstancedANGLE(mode, first, count, primcount);
}

void ANGLEInstancedArrays::drawElementsInstancedANGLE(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, GC3Dsizei primcount)
{
    if (isLost())
        return;

    m_context->drawElementsInstancedANGLE(mode, count, type, offset, primcount);
}

void ANGLEInstancedArrays::vertexAttribDivisorANGLE(GC3Duint index, GC3Duint divisor)
{
    if (isLost())
        return;

    m_context->vertexAttribDivisorANGLE(index, divisor);
}

} // namespace WebCore
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTypes.h"

#include "SkColor.h"
#include "SkFloatingPoint.h"
#include "SkMaskGamma.h"

SkScalar SkSRGBLuminance::toLuma(SkScalar luminance) const {
    //The magic numbers are derived from the sRGB specification.
    //See http://www.color.org/chardata/rgb/srgb.xalter .
    if (luminance <= SkFloatToScalar(0.04045f)) {
        return luminance / SkFloatToScalar(12.92f);
    }
    return SkScalarPow((luminance + SkFloatToScalar(0.055f)) / SkFloatToScalar(1.055f),
                       SkFloatToScalar(2.4f));
}

SkScalar SkSRGBLuminance::fromLuma(SkScalar luma) const {
    //The magic numbers are derived from the sRGB specification.
    //See http://www.color.org/chardata/rgb/srgb.xalter .
    if (luma <= SkFloatToScalar(0.0031308f)) {
        return luma * SkFloatToScalar(12.92f);
    }
    return SkFloatToScalar(1.055f) * SkScalarPow(luma, SkScalarInvert(SkFloatToScalar(2.4f)))
           - SkFloatToScalar(0.055f);
}

SkGammaLuminance::SkGammaLuminance(SkScalar gamma)
    : fGamma(gamma)
    , fGammaInverse(SkScalarInvert(gamma)) {
}

float SkGammaLuminance::toLuma(SkScalar luminance) const {
    return SkScalarPow(luminance, fGamma);
}

float SkGammaLuminance::fromLuma(SkScalar luma) const {
    return SkScalarPow(luma, fGammaInverse);
}

static float apply_contrast(float srca, float contrast) {
    return srca + ((1.0f - srca) * contrast * srca);
}

void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast,
                                const SkColorSpaceLuminance& srcConvert,
                                const SkColorSpaceLuminance& dstConvert) {
    const float src = (float)srcI / 255.0f;
    const float linSrc = srcConvert.toLuma(src);
    //Guess at the dst. The perceptual inverse provides smaller visual
    //discontinuities when slight changes to desaturated colors cause a channel
    //to map to a different correcting lut with neighboring srcI.
    //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 .
    const float dst = 1.0f - src;
    const float linDst = dstConvert.toLuma(dst);

    //Contrast value tapers off to 0 as the src luminance becomes white
    const float adjustedContrast = SkScalarToFloat(contrast) * linDst;
    const float step = 1.0f / 255.0f;

    //Remove discontinuity and instability when src is close to dst.
    //The value 1/256 is arbitrary and appears to contain the instability.
    if (fabs(src - dst) < (1.0f / 256.0f)) {
        float rawSrca = 0.0f;
        for (int i = 0; i < 256; ++i, rawSrca += step) {
            float srca = apply_contrast(rawSrca, adjustedContrast);
            table[i] = SkToU8(sk_float_round2int(255.0f * srca));
        }
    } else {
        float rawSrca = 0.0f;
        for (int i = 0; i < 256; ++i, rawSrca += step) {
            float srca = apply_contrast(rawSrca, adjustedContrast);
            SkASSERT(srca <= 1.0f);
            float dsta = 1.0f - srca;

            //Calculate the output we want.
            float linOut = (linSrc * srca + dsta * linDst);
            SkASSERT(linOut <= 1.0f);
            float out = dstConvert.fromLuma(linOut);

            //Undo what the blit blend will do.
            float result = (out - dst) / (src - dst);
            SkASSERT(sk_float_round2int(255.0f * result) <= 255);

            table[i] = SkToU8(sk_float_round2int(255.0f * result));
        }
    }
}
<commit_msg>Fix mask gamma rounding issues on x87. https://codereview.appspot.com/6497091/<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTypes.h"

#include "SkColor.h"
#include "SkFloatingPoint.h"
#include "SkMaskGamma.h"

SkScalar SkSRGBLuminance::toLuma(SkScalar luminance) const {
    //The magic numbers are derived from the sRGB specification.
    //See http://www.color.org/chardata/rgb/srgb.xalter .
    if (luminance <= SkFloatToScalar(0.04045f)) {
        return luminance / SkFloatToScalar(12.92f);
    }
    return SkScalarPow((luminance + SkFloatToScalar(0.055f)) / SkFloatToScalar(1.055f),
                       SkFloatToScalar(2.4f));
}

SkScalar SkSRGBLuminance::fromLuma(SkScalar luma) const {
    //The magic numbers are derived from the sRGB specification.
    //See http://www.color.org/chardata/rgb/srgb.xalter .
    if (luma <= SkFloatToScalar(0.0031308f)) {
        return luma * SkFloatToScalar(12.92f);
    }
    return SkFloatToScalar(1.055f) * SkScalarPow(luma, SkScalarInvert(SkFloatToScalar(2.4f)))
           - SkFloatToScalar(0.055f);
}

SkGammaLuminance::SkGammaLuminance(SkScalar gamma)
    : fGamma(gamma)
    , fGammaInverse(SkScalarInvert(gamma)) {
}

float SkGammaLuminance::toLuma(SkScalar luminance) const {
    return SkScalarPow(luminance, fGamma);
}

float SkGammaLuminance::fromLuma(SkScalar luma) const {
    return SkScalarPow(luma, fGammaInverse);
}

static float apply_contrast(float srca, float contrast) {
    return srca + ((1.0f - srca) * contrast * srca);
}

void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast,
                                       const SkColorSpaceLuminance& srcConvert,
                                       const SkColorSpaceLuminance& dstConvert) {
    const float src = (float)srcI / 255.0f;
    const float linSrc = srcConvert.toLuma(src);
    //Guess at the dst. The perceptual inverse provides smaller visual
    //discontinuities when slight changes to desaturated colors cause a channel
    //to map to a different correcting lut with neighboring srcI.
    //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 .
    const float dst = 1.0f - src;
    const float linDst = dstConvert.toLuma(dst);

    //Contrast value tapers off to 0 as the src luminance becomes white
    const float adjustedContrast = SkScalarToFloat(contrast) * linDst;

    //Remove discontinuity and instability when src is close to dst.
    //The value 1/256 is arbitrary and appears to contain the instability.
    if (fabs(src - dst) < (1.0f / 256.0f)) {
        float ii = 0.0f;
        for (int i = 0; i < 256; ++i, ii += 1.0f) {
            float rawSrca = ii / 255.0f;
            float srca = apply_contrast(rawSrca, adjustedContrast);
            table[i] = SkToU8(sk_float_round2int(255.0f * srca));
        }
    } else {
        // Avoid slow int to float conversion.
        float ii = 0.0f;
        for (int i = 0; i < 256; ++i, ii += 1.0f) {
            // 'rawSrca += 1.0f / 255.0f' and even
            // 'rawSrca = i * (1.0f / 255.0f)' can add up to more than 1.0f.
            // When this happens the table[255] == 0x0 instead of 0xff.
            // See http://code.google.com/p/chromium/issues/detail?id=146466
            float rawSrca = ii / 255.0f;
            float srca = apply_contrast(rawSrca, adjustedContrast);
            SkASSERT(srca <= 1.0f);
            float dsta = 1.0f - srca;

            //Calculate the output we want.
            float linOut = (linSrc * srca + dsta * linDst);
            SkASSERT(linOut <= 1.0f);
            float out = dstConvert.fromLuma(linOut);

            //Undo what the blit blend will do.
            float result = (out - dst) / (src - dst);
            SkASSERT(sk_float_round2int(255.0f * result) <= 255);

            table[i] = SkToU8(sk_float_round2int(255.0f * result));
        }
    }
}
<|endoftext|>