<commit_before>/*
 * SessionRequest.hpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef SESSION_REQUEST_HPP
#define SESSION_REQUEST_HPP

#include <core/Error.hpp>
#include <core/system/Environment.hpp>

#include <session/http/SessionRequest.hpp>

#if !defined(_WIN32)
#include <core/http/TcpIpBlockingClient.hpp>
#include <core/http/LocalStreamBlockingClient.hpp>
#include <core/http/ConnectionRetryProfile.hpp>
#else
#include <core/http/NamedPipeBlockingClient.hpp>
#endif

#if !defined(_WIN32)
#include <session/SessionLocalStreams.hpp>
#endif

#include <session/SessionConstants.hpp>

namespace rstudio {
namespace session {
namespace http {

// this function sends an request directly to the session; it's inlined so that
// it can be used both from the postback executable (which does not link with
// rsession) and the session itself
inline core::Error sendSessionRequest(const std::string& uri,
      const std::string& body, core::http::Response* pResponse)
{
   // build request
   core::http::Request request;
   request.setMethod("POST");
   request.setUri(uri);
   request.setHeader("Accept", "*/*");
   request.setHeader("Connection", "close");
   request.setBody(body);

#ifdef _WIN32
   // get local peer
   std::string pipeName = core::system::getenv("RS_LOCAL_PEER");
   request.setHeader("X-Shared-Secret",
                       core::system::getenv("RS_SHARED_SECRET"));
   return core::http::sendRequest(pipeName,
                            request,
                            core::http::ConnectionRetryProfile(
                                  boost::posix_time::seconds(10),
                                  boost::posix_time::milliseconds(50)),
                            pResponse);
#else
   std::string tcpipPort = core::system::getenv(kRSessionStandalonePortNumber);
   if (tcpipPort.empty())
   {
      // if no standalone port, make an authenticated session request
      tcpipPort = core::system::getenv(kRSessionPortNumber);
      request.setHeader("X-Shared-Secret",
                          core::system::getenv("RS_SHARED_SECRET"));
   }
   if (!tcpipPort.empty())
   {
      return core::http::sendRequest("127.0.0.1", tcpipPort, request,
            pResponse);
   }
   else
   {
      // determine stream path
      std::string stream = core::system::getenv(kRStudioSessionStream);
      core::FilePath streamPath = session::local_streams::streamPath(stream);
      return core::http::sendRequest(streamPath, request, pResponse);
   }
#endif

   return core::Success();
}

} // namespace http
} // namespace session
} // namespace rstudio

#endif
<commit_msg>add support for domain sockets for console input on Linux desktop<commit_after>/*
 * SessionRequest.hpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef SESSION_REQUEST_HPP
#define SESSION_REQUEST_HPP

#include <core/Error.hpp>
#include <core/system/Environment.hpp>

#include <session/http/SessionRequest.hpp>

#if !defined(_WIN32)
#include <core/http/TcpIpBlockingClient.hpp>
#include <core/http/LocalStreamBlockingClient.hpp>
#include <core/http/ConnectionRetryProfile.hpp>
#else
#include <core/http/NamedPipeBlockingClient.hpp>
#endif

#if !defined(_WIN32)
#include <session/SessionLocalStreams.hpp>
#endif

#include <session/SessionConstants.hpp>

namespace rstudio {
namespace session {
namespace http {

// this function sends an request directly to the session; it's inlined so that
// it can be used both from the postback executable (which does not link with
// rsession) and the session itself
inline core::Error sendSessionRequest(const std::string& uri,
      const std::string& body, core::http::Response* pResponse)
{
   // build request
   core::http::Request request;
   request.setMethod("POST");
   request.setUri(uri);
   request.setHeader("Accept", "*/*");
   request.setHeader("Connection", "close");
   request.setBody(body);

#ifdef _WIN32
   // get local peer
   std::string pipeName = core::system::getenv("RS_LOCAL_PEER");
   request.setHeader("X-Shared-Secret",
                       core::system::getenv("RS_SHARED_SECRET"));
   return core::http::sendRequest(pipeName,
                            request,
                            core::http::ConnectionRetryProfile(
                                  boost::posix_time::seconds(10),
                                  boost::posix_time::milliseconds(50)),
                            pResponse);
#else
   std::string tcpipPort = core::system::getenv(kRSessionStandalonePortNumber);

#ifdef __APPLE__
   // on OS X desktop, we use HTTP
   if (tcpipPort.empty())
   {
      // if no standalone port, make an authenticated session request
      tcpipPort = core::system::getenv(kRSessionPortNumber);
      request.setHeader("X-Shared-Secret",
                          core::system::getenv("RS_SHARED_SECRET"));
   }
#endif

   if (!tcpipPort.empty())
   {
      return core::http::sendRequest("127.0.0.1", tcpipPort, request,
            pResponse);
   }
   else
   {
      // determine stream path -- check server environment variable first
      core::FilePath streamPath;
      std::string stream = core::system::getenv(kRStudioSessionStream);
      if (stream.empty())
      {
         // if no server environment variable, check desktop variant
         streamPath = core::FilePath(core::system::getenv("RS_LOCAL_PEER"));
         request.setHeader("X-Shared-Secret",
                             core::system::getenv("RS_SHARED_SECRET"));
      }
      else
      {
         streamPath = session::local_streams::streamPath(stream);
      }
      return core::http::sendRequest(streamPath, request, pResponse);
   }
#endif

   return core::Success();
}

} // namespace http
} // namespace session
} // namespace rstudio

#endif
<|endoftext|>


<commit_before>/*
 * NotebookQueueUnit.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "NotebookQueueUnit.hpp"

#include <session/SessionModuleContext.hpp>

#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/session/RSession.hpp>

#define kQueueUnitCode       "code"
#define kQueueUnitDocId      "doc_id"
#define kQueueUnitChunkId    "chunk_id"
#define kQueueUnitCompleted  "completed"
#define kQueueUnitPending    "pending"
#define kQueueUnitExecuting  "executing"
#define kQueueUnitExecMode   "exec_mode"
#define kQueueUnitExecScope  "exec_scope"
#define kQueueUnitRangeStart "start"
#define kQueueUnitRangeStop  "stop"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

Error fillExecRange(const json::Array& in, std::list<ExecRange>* pOut)
{
   // process arrays
   BOOST_FOREACH(const json::Value val, in)
   {
      // ignore non-value types
      if (val.type() != json::ObjectType)
         continue;

      ExecRange range(0, 0);
      Error error = ExecRange::fromJson(val.get_obj(), &range);
      if (error)
         return error;

      pOut->push_back(range);
   }
   return Success();
}

void fillJsonRange(const std::list<ExecRange>& in, json::Array* pOut)
{
   BOOST_FOREACH(const ExecRange range, in)
   {
      pOut->push_back(range.toJson());
   }
}

} // anonymous namespace

Error ExecRange::fromJson(const json::Object& source,
                          ExecRange* pRange)
{
   return json::readObject(source,
         kQueueUnitRangeStart, &pRange->start,
         kQueueUnitRangeStop,  &pRange->stop);
}

json::Object ExecRange::toJson() const
{
   json::Object jsonRange;
   jsonRange[kQueueUnitRangeStart] = start;
   jsonRange[kQueueUnitRangeStop] = stop;
   return jsonRange;
}

void ExecRange::extendTo(const ExecRange& other)
{
   start = std::min(start, other.start);
   stop  = std::max(stop, other.stop);
}

bool ExecRange::empty()
{
   return start == 0 && stop == 0;
}

Error NotebookQueueUnit::fromJson(const json::Object& source,
      boost::shared_ptr<NotebookQueueUnit>* pUnit)
{
   // extract contained unit for manipulation
   NotebookQueueUnit& unit = *pUnit->get();

   // extract top-level values
   json::Array completed, pending;
   int execMode, execScope;
   Error error = json::readObject(source,
         kQueueUnitCode,      &unit.code_,
         kQueueUnitDocId,     &unit.docId_,
         kQueueUnitChunkId,   &unit.chunkId_,
         kQueueUnitCompleted, &completed,
         kQueueUnitPending,   &pending,
         kQueueUnitExecMode,  &execMode,
         kQueueUnitExecScope, &execScope);
   if (error)
      LOG_ERROR(error);

   unit.execMode_ = static_cast<ExecMode>(execMode);
   unit.execScope_ = static_cast<ExecScope>(execScope);

   // process arrays
   error = fillExecRange(completed, &unit.completed_);
   if (error)
      LOG_ERROR(error);
   error = fillExecRange(pending, &unit.pending_);
   if (error)
      LOG_ERROR(error);
   return Success();
}

Error NotebookQueueUnit::parseOptions(json::Object* pOptions)
{
   // evaluate this chunk's options in R
   r::sexp::Protect protect;
   SEXP sexpOptions = R_NilValue;
   Error error = r::exec::RFunction(".rs.evaluateChunkOptions", code_)
                                   .call(&sexpOptions, &protect);
   if (error)
      return error;

   // convert to JSON
   json::Value jsonOptions;
   error = r::json::jsonValueFromList(sexpOptions, &jsonOptions);
   if (jsonOptions.type() == json::ArrayType &&
       jsonOptions.get_array().empty())
   {
      // treat empty array as empty object
      *pOptions = json::Object();
   }
   else if (jsonOptions.type() != json::ObjectType)
   {
      return Error(json::errc::ParseError, ERROR_LOCATION);
   }
   else
   {
      *pOptions = jsonOptions.get_obj();
   }

   return Success();
}

Error NotebookQueueUnit::innerCode(std::string* pCode)
{
   return r::exec::RFunction(".rs.extractChunkInnerCode", code_).call(pCode);
}

void NotebookQueueUnit::updateFrom(const NotebookQueueUnit& other)
{
   // replace code
   code_ = other.code();

   // we don't support removing or changing executable ranges, so process only
   // additions
   std::list<ExecRange>::iterator i = pending_.begin();
   for (std::list<ExecRange>::const_iterator o = other.pending_.begin();
        o != other.pending_.end();
        o ++)
   {
      if (i == pending_.end())
      {
         // past end of our own range, so begin inserting elements from the
         // other unit's range
         pending_.insert(i, *o);
      }
      else
      {
         i++;
      }
   }
}

json::Object NotebookQueueUnit::toJson() const
{
   // process arrays
   json::Array completed, pending;
   fillJsonRange(completed_, &completed);
   fillJsonRange(pending_, &pending);

   // emit top-level values
   json::Object unit;
   unit[kQueueUnitCode]      = code_;
   unit[kQueueUnitDocId]     = docId_;
   unit[kQueueUnitChunkId]   = chunkId_;
   unit[kQueueUnitCompleted] = completed;
   unit[kQueueUnitPending]   = pending;
   unit[kQueueUnitExecMode]  = execMode_;
   unit[kQueueUnitExecScope] = execScope_;
   unit[kQueueUnitExecuting] = executing_.toJson();

   return unit;
}

std::string NotebookQueueUnit::popExecRange(ExecRange* pRange,
      ExpressionMode mode)
{
   // extract next range to execute
   ExecRange& range = *pending_.begin();
   int start = range.start;
   int stop = range.stop;

   // use the first line of the range if it's multi-line
   size_t idx = code_.find('\n', start + 1);
   if (idx != std::string::npos && static_cast<int>(idx) < stop)
   {
      stop = idx;

      // adjust the range to account for the code we're about to send
      range.start = idx + 1;
   }
   else
   {
      // not multi line, remove range entirely
      pending_.pop_front();
   }

   // mark completed and extract from code
   if (mode == ExprModeNew || executing_.empty())
      executing_ = ExecRange(start, stop);
   else
      executing_.extendTo(ExecRange(start, stop));

   completed_.push_back(executing_);
   std::string code = code_.substr(start, stop - start);

   // return values to caller
   if (pRange)
      *pRange = executing_;

   return code;
}

std::string NotebookQueueUnit::docId() const
{
   return docId_;
}

std::string NotebookQueueUnit::chunkId() const
{
   return chunkId_;
}

std::string NotebookQueueUnit::code() const
{
   return code_;
}

bool NotebookQueueUnit::complete() const
{
   return pending_.empty();
}

ExecScope NotebookQueueUnit::execScope() const
{
   return execScope_;
}

ExecMode NotebookQueueUnit::execMode() const
{
   return execMode_;
}

std::string NotebookQueueUnit::executingCode() const
{
   return code_.substr(executing_.start, executing_.stop - executing_.start);
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<commit_msg>send single blank lines individually<commit_after>/*
 * NotebookQueueUnit.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "NotebookQueueUnit.hpp"

#include <session/SessionModuleContext.hpp>

#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>

#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/session/RSession.hpp>

#define kQueueUnitCode       "code"
#define kQueueUnitDocId      "doc_id"
#define kQueueUnitChunkId    "chunk_id"
#define kQueueUnitCompleted  "completed"
#define kQueueUnitPending    "pending"
#define kQueueUnitExecuting  "executing"
#define kQueueUnitExecMode   "exec_mode"
#define kQueueUnitExecScope  "exec_scope"
#define kQueueUnitRangeStart "start"
#define kQueueUnitRangeStop  "stop"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

Error fillExecRange(const json::Array& in, std::list<ExecRange>* pOut)
{
   // process arrays
   BOOST_FOREACH(const json::Value val, in)
   {
      // ignore non-value types
      if (val.type() != json::ObjectType)
         continue;

      ExecRange range(0, 0);
      Error error = ExecRange::fromJson(val.get_obj(), &range);
      if (error)
         return error;

      pOut->push_back(range);
   }
   return Success();
}

void fillJsonRange(const std::list<ExecRange>& in, json::Array* pOut)
{
   BOOST_FOREACH(const ExecRange range, in)
   {
      pOut->push_back(range.toJson());
   }
}

} // anonymous namespace

Error ExecRange::fromJson(const json::Object& source,
                          ExecRange* pRange)
{
   return json::readObject(source,
         kQueueUnitRangeStart, &pRange->start,
         kQueueUnitRangeStop,  &pRange->stop);
}

json::Object ExecRange::toJson() const
{
   json::Object jsonRange;
   jsonRange[kQueueUnitRangeStart] = start;
   jsonRange[kQueueUnitRangeStop] = stop;
   return jsonRange;
}

void ExecRange::extendTo(const ExecRange& other)
{
   start = std::min(start, other.start);
   stop  = std::max(stop, other.stop);
}

bool ExecRange::empty()
{
   return start == 0 && stop == 0;
}

Error NotebookQueueUnit::fromJson(const json::Object& source,
      boost::shared_ptr<NotebookQueueUnit>* pUnit)
{
   // extract contained unit for manipulation
   NotebookQueueUnit& unit = *pUnit->get();

   // extract top-level values
   json::Array completed, pending;
   int execMode, execScope;
   Error error = json::readObject(source,
         kQueueUnitCode,      &unit.code_,
         kQueueUnitDocId,     &unit.docId_,
         kQueueUnitChunkId,   &unit.chunkId_,
         kQueueUnitCompleted, &completed,
         kQueueUnitPending,   &pending,
         kQueueUnitExecMode,  &execMode,
         kQueueUnitExecScope, &execScope);
   if (error)
      LOG_ERROR(error);

   unit.execMode_ = static_cast<ExecMode>(execMode);
   unit.execScope_ = static_cast<ExecScope>(execScope);

   // process arrays
   error = fillExecRange(completed, &unit.completed_);
   if (error)
      LOG_ERROR(error);
   error = fillExecRange(pending, &unit.pending_);
   if (error)
      LOG_ERROR(error);
   return Success();
}

Error NotebookQueueUnit::parseOptions(json::Object* pOptions)
{
   // evaluate this chunk's options in R
   r::sexp::Protect protect;
   SEXP sexpOptions = R_NilValue;
   Error error = r::exec::RFunction(".rs.evaluateChunkOptions", code_)
                                   .call(&sexpOptions, &protect);
   if (error)
      return error;

   // convert to JSON
   json::Value jsonOptions;
   error = r::json::jsonValueFromList(sexpOptions, &jsonOptions);
   if (jsonOptions.type() == json::ArrayType &&
       jsonOptions.get_array().empty())
   {
      // treat empty array as empty object
      *pOptions = json::Object();
   }
   else if (jsonOptions.type() != json::ObjectType)
   {
      return Error(json::errc::ParseError, ERROR_LOCATION);
   }
   else
   {
      *pOptions = jsonOptions.get_obj();
   }

   return Success();
}

Error NotebookQueueUnit::innerCode(std::string* pCode)
{
   return r::exec::RFunction(".rs.extractChunkInnerCode", code_).call(pCode);
}

void NotebookQueueUnit::updateFrom(const NotebookQueueUnit& other)
{
   // replace code
   code_ = other.code();

   // we don't support removing or changing executable ranges, so process only
   // additions
   std::list<ExecRange>::iterator i = pending_.begin();
   for (std::list<ExecRange>::const_iterator o = other.pending_.begin();
        o != other.pending_.end();
        o ++)
   {
      if (i == pending_.end())
      {
         // past end of our own range, so begin inserting elements from the
         // other unit's range
         pending_.insert(i, *o);
      }
      else
      {
         i++;
      }
   }
}

json::Object NotebookQueueUnit::toJson() const
{
   // process arrays
   json::Array completed, pending;
   fillJsonRange(completed_, &completed);
   fillJsonRange(pending_, &pending);

   // emit top-level values
   json::Object unit;
   unit[kQueueUnitCode]      = code_;
   unit[kQueueUnitDocId]     = docId_;
   unit[kQueueUnitChunkId]   = chunkId_;
   unit[kQueueUnitCompleted] = completed;
   unit[kQueueUnitPending]   = pending;
   unit[kQueueUnitExecMode]  = execMode_;
   unit[kQueueUnitExecScope] = execScope_;
   unit[kQueueUnitExecuting] = executing_.toJson();

   return unit;
}

std::string NotebookQueueUnit::popExecRange(ExecRange* pRange,
      ExpressionMode mode)
{
   // extract next range to execute
   ExecRange& range = *pending_.begin();
   int start = range.start;
   int stop = range.stop;

   // if this is a blank line, submit it by itself
   if (code_.at(start) == '\n')
   {
      stop = start + 1;
      range.start = stop;
   }
   else
   {
      // use the first line of the range if it's multi-line
      size_t idx = code_.find('\n', start + 1);
      if (idx != std::string::npos && static_cast<int>(idx) < stop)
      {
         stop = idx;

         // adjust the range to account for the code we're about to send
         range.start = idx + 1;
      }
      else
      {
         // not multi line, remove range entirely
         pending_.pop_front();
      }
   }

   // mark completed and extract from code
   if (mode == ExprModeNew || executing_.empty())
      executing_ = ExecRange(start, stop);
   else
      executing_.extendTo(ExecRange(start, stop));

   completed_.push_back(executing_);
   std::string code = code_.substr(start, stop - start);

   // return values to caller
   if (pRange)
      *pRange = executing_;

   return code;
}

std::string NotebookQueueUnit::docId() const
{
   return docId_;
}

std::string NotebookQueueUnit::chunkId() const
{
   return chunkId_;
}

std::string NotebookQueueUnit::code() const
{
   return code_;
}

bool NotebookQueueUnit::complete() const
{
   return pending_.empty();
}

ExecScope NotebookQueueUnit::execScope() const
{
   return execScope_;
}

ExecMode NotebookQueueUnit::execMode() const
{
   return execMode_;
}

std::string NotebookQueueUnit::executingCode() const
{
   return code_.substr(executing_.start, executing_.stop - executing_.start);
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<|endoftext|>


<commit_before>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "perl_callbacks.h"
#include "embedperl.h"
#include <assert.h>

#define MAX_EMBED_PERL 10

// Totally thread-unsafe...
static EmbedPerl *ePerl[MAX_EMBED_PERL];
static int numEmbedPerl = 0;

extern "C" {
void xs_init(pTHX);

/***** CALLBACKS *****/

#define FOR_EVERY_EMBED(UNIQUEID,CALLBACK) \
  for( int i = 0; i < numEmbedPerl; ++i ) \
     if( strcmp(ePerl[i]->uniqueid(),UNIQUEID)==0 && ePerl[i]->CALLBACK )

void emoteEmbed(const char *uniqueid, const char *receiver, const char *message)
{
  printf("***Callback*** Send emote to %s (on %s): %s\n", receiver, uniqueid, message);
  FOR_EVERY_EMBED(uniqueid,emoteCallback) {
    ePerl[i]->emoteCallback( uniqueid, receiver, message, ePerl[i]->data );
    return;
  }
  fprintf(stderr,"[CallbackError] No handler for Emote callback (uniqueid=%s)\n", uniqueid);
}

void privmsgEmbed(const char *uniqueid, const char *receiver, const char *message)
{
  printf("***Callback*** Send privmsg to %s (on %s): %s\n", receiver, uniqueid, message);
  FOR_EVERY_EMBED(uniqueid,privmsgCallback) {
    ePerl[i]->privmsgCallback( uniqueid, receiver, message, ePerl[i]->data );
    return;
  }
  fprintf(stderr,"[CallbackError] No handler for Privmsg callback (uniqueid=%s)\n", uniqueid);
}

const char *getPropertyEmbed(const char *uniqueid, const char *variable)
{
  FOR_EVERY_EMBED(uniqueid,getPropertyCallback) {
    return ePerl[i]->getPropertyCallback( uniqueid, variable, ePerl[i]->data );
  }
}

void setPropertyEmbed(const char *uniqueid, const char *variable, const char *value)
{
  FOR_EVERY_EMBED(uniqueid,setPropertyCallback) {
    ePerl[i]->setPropertyCallback( uniqueid, variable, value, ePerl[i]->data );
    return;
  }
}

void unsetPropertyEmbed(const char *uniqueid, const char *variable)
{
  FOR_EVERY_EMBED(uniqueid,unsetPropertyCallback) {
    ePerl[i]->unsetPropertyCallback( uniqueid, variable, ePerl[i]->data );
    return;
  }
}

/***** END CALLBACKS ****/
}

EmbedPerl::EmbedPerl(const char *uniqueid)
: emoteCallback(0)
, privmsgCallback(0)
{
  if( MAX_EMBED_PERL == numEmbedPerl )
  {
    fprintf(stderr, "Too many EmbedPerls. Raise MAX_EMBED_PERL\n");
    abort();
  }

  for( int i = 0; i < numEmbedPerl; ++i )
  {
    if( strcmp(ePerl[i]->uniqueid(), uniqueid) != 0 )
    {
      fprintf(stderr,"EmbedPerl created for a duplicate uniqueid.\n");
      abort();
    }
  }
  uniqueid_ = (char*)malloc(strlen(uniqueid));
  strcpy(uniqueid_, uniqueid);
  ePerl[numEmbedPerl++] = this;

  perl = perl_alloc();
  perl_construct(perl);

  char *argv[] = {"", "dazeus2_api_emulate.pl"};
  perl_parse(perl, xs_init, 1, argv, NULL);

  init();
}

EmbedPerl::~EmbedPerl()
{
  fprintf(stderr, "EmbedPerl destructor\n");
  perl_destruct(perl);
  perl_free(perl);
}

const char *EmbedPerl::uniqueid() const
{
  return uniqueid_;
}

void EmbedPerl::setCallbacks( void (*emoteCallback)  (const char*, const char*, const char*, void*),
                              void (*privmsgCallback)(const char*, const char*, const char*, void*),
                              const char* (*getPropertyCallback)(const char*, const char*, void*),
                              void (*setPropertyCallback)(const char*, const char*, const char*, void*),
                              void (*unsetPropertyCallback)(const char*, const char*, void*),
                              void *data )
{
  this->emoteCallback = emoteCallback;
  this->privmsgCallback = privmsgCallback;
  this->getPropertyCallback = getPropertyCallback;
  this->setPropertyCallback = setPropertyCallback;
  this->unsetPropertyCallback = unsetPropertyCallback;
  this->data = data;
}

void EmbedPerl::init()
{
  fprintf(stderr, "EmbedPerl::init()\n");
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(uniqueid_, strlen(uniqueid_)));
  PUTBACK;
  call_pv("init", G_SCALAR);
  SPAGAIN;
  PUTBACK;
  FREETMPS;
  LEAVE;
}

void EmbedPerl::message(const char *from, const char *to, const char *msg)
{
  fprintf(stderr, "EmbedPerl::message(%s,%s,%s)\n", from, to, msg);
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(from, strlen(from)) );
  XPUSHs( newSVpv(to,   strlen(to))   );
  XPUSHs( newSVpv(msg,  strlen(msg))  );
  XPUSHs( newSVpv(msg,  strlen(msg))  );
  PUTBACK;
  call_pv("message", G_SCALAR);
  SPAGAIN;
  int result = POPi;
  PUTBACK;
  FREETMPS;
  LEAVE;
  fprintf(stderr, "... message(...)=%d\n", result);
}

bool EmbedPerl::loadModule(const char *module)
{
  fprintf(stderr, "EmbedPerl::loadModule(%s)", module);
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(module, strlen(module)) );
  PUTBACK;
  call_pv("loadModule", G_SCALAR);
  SPAGAIN;
  int result = POPi;
  PUTBACK;
  FREETMPS;
  LEAVE;
  fprintf(stderr, "=%d\n", result);
  return result != 0;
}
<commit_msg>Made debug in EmbedPerl optional, disabled now.<commit_after>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "perl_callbacks.h"
#include "embedperl.h"
#include <assert.h>

#define MAX_EMBED_PERL 10
// #define DEBUG

// Totally thread-unsafe...
static EmbedPerl *ePerl[MAX_EMBED_PERL];
static int numEmbedPerl = 0;

extern "C" {
void xs_init(pTHX);

/***** CALLBACKS *****/

#define FOR_EVERY_EMBED(UNIQUEID,CALLBACK) \
  for( int i = 0; i < numEmbedPerl; ++i ) \
     if( strcmp(ePerl[i]->uniqueid(),UNIQUEID)==0 && ePerl[i]->CALLBACK )

void emoteEmbed(const char *uniqueid, const char *receiver, const char *message)
{
#ifdef DEBUG
  printf("***Callback*** Send emote to %s (on %s): %s\n", receiver, uniqueid, message);
#endif
  FOR_EVERY_EMBED(uniqueid,emoteCallback) {
    ePerl[i]->emoteCallback( uniqueid, receiver, message, ePerl[i]->data );
    return;
  }
  fprintf(stderr,"[CallbackError] No handler for Emote callback (uniqueid=%s)\n", uniqueid);
}

void privmsgEmbed(const char *uniqueid, const char *receiver, const char *message)
{
#ifdef DEBUG
  printf("***Callback*** Send privmsg to %s (on %s): %s\n", receiver, uniqueid, message);
#endif
  FOR_EVERY_EMBED(uniqueid,privmsgCallback) {
    ePerl[i]->privmsgCallback( uniqueid, receiver, message, ePerl[i]->data );
    return;
  }
  fprintf(stderr,"[CallbackError] No handler for Privmsg callback (uniqueid=%s)\n", uniqueid);
}

const char *getPropertyEmbed(const char *uniqueid, const char *variable)
{
  FOR_EVERY_EMBED(uniqueid,getPropertyCallback) {
    return ePerl[i]->getPropertyCallback( uniqueid, variable, ePerl[i]->data );
  }
}

void setPropertyEmbed(const char *uniqueid, const char *variable, const char *value)
{
  FOR_EVERY_EMBED(uniqueid,setPropertyCallback) {
    ePerl[i]->setPropertyCallback( uniqueid, variable, value, ePerl[i]->data );
    return;
  }
}

void unsetPropertyEmbed(const char *uniqueid, const char *variable)
{
  FOR_EVERY_EMBED(uniqueid,unsetPropertyCallback) {
    ePerl[i]->unsetPropertyCallback( uniqueid, variable, ePerl[i]->data );
    return;
  }
}

/***** END CALLBACKS ****/
}

EmbedPerl::EmbedPerl(const char *uniqueid)
: emoteCallback(0)
, privmsgCallback(0)
{
  if( MAX_EMBED_PERL == numEmbedPerl )
  {
    fprintf(stderr, "Too many EmbedPerls. Raise MAX_EMBED_PERL\n");
    abort();
  }

  for( int i = 0; i < numEmbedPerl; ++i )
  {
    if( strcmp(ePerl[i]->uniqueid(), uniqueid) != 0 )
    {
      fprintf(stderr,"EmbedPerl created for a duplicate uniqueid.\n");
      abort();
    }
  }
  uniqueid_ = (char*)malloc(strlen(uniqueid));
  strcpy(uniqueid_, uniqueid);
  ePerl[numEmbedPerl++] = this;

  perl = perl_alloc();
  perl_construct(perl);

  char *argv[] = {"", "dazeus2_api_emulate.pl"};
  perl_parse(perl, xs_init, 1, argv, NULL);

  init();
}

EmbedPerl::~EmbedPerl()
{
#ifdef DEBUG
  fprintf(stderr, "EmbedPerl destructor\n");
#endif
  perl_destruct(perl);
  perl_free(perl);
}

const char *EmbedPerl::uniqueid() const
{
  return uniqueid_;
}

void EmbedPerl::setCallbacks( void (*emoteCallback)  (const char*, const char*, const char*, void*),
                              void (*privmsgCallback)(const char*, const char*, const char*, void*),
                              const char* (*getPropertyCallback)(const char*, const char*, void*),
                              void (*setPropertyCallback)(const char*, const char*, const char*, void*),
                              void (*unsetPropertyCallback)(const char*, const char*, void*),
                              void *data )
{
  this->emoteCallback = emoteCallback;
  this->privmsgCallback = privmsgCallback;
  this->getPropertyCallback = getPropertyCallback;
  this->setPropertyCallback = setPropertyCallback;
  this->unsetPropertyCallback = unsetPropertyCallback;
  this->data = data;
}

void EmbedPerl::init()
{
#ifdef DEBUG
  fprintf(stderr, "EmbedPerl::init()\n");
#endif
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(uniqueid_, strlen(uniqueid_)));
  PUTBACK;
  call_pv("init", G_SCALAR);
  SPAGAIN;
  PUTBACK;
  FREETMPS;
  LEAVE;
}

void EmbedPerl::message(const char *from, const char *to, const char *msg)
{
#ifdef DEBUG
  fprintf(stderr, "EmbedPerl::message(%s,%s,%s)\n", from, to, msg);
#endif
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(from, strlen(from)) );
  XPUSHs( newSVpv(to,   strlen(to))   );
  XPUSHs( newSVpv(msg,  strlen(msg))  );
  XPUSHs( newSVpv(msg,  strlen(msg))  );
  PUTBACK;
  call_pv("message", G_SCALAR);
  SPAGAIN;
  int result = POPi;
  PUTBACK;
  FREETMPS;
  LEAVE;
#ifdef DEBUG
  fprintf(stderr, "... message(...)=%d\n", result);
#endif
}

bool EmbedPerl::loadModule(const char *module)
{
#ifdef DEBUG
  fprintf(stderr, "EmbedPerl::loadModule(%s)", module);
#endif
  PerlInterpreter *my_perl = perl;
  dSP;
  ENTER;
  SAVETMPS;
  PUSHMARK(SP);
  XPUSHs( newSVpv(module, strlen(module)) );
  PUTBACK;
  call_pv("loadModule", G_SCALAR);
  SPAGAIN;
  int result = POPi;
  PUTBACK;
  FREETMPS;
  LEAVE;
#ifdef DEBUG
  fprintf(stderr, "=%d\n", result);
#endif
  return result != 0;
}
<|endoftext|>


<commit_before>/*
 Adapted from ciUI's Moving Graph by @brucelane with permission from @rezaali
 https://github.com/rezaali/ciUI
*/

#include "Graph.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace MinimalUI;

int MovingGraph::DEFAULT_HEIGHT = UIElement::DEFAULT_HEIGHT;
int MovingGraph::DEFAULT_WIDTH = 96;

// common initialization
void MovingGraph::init()
{
	// initialize unique variables
	mMin = hasParam("min") ? getParam<float>("min") : 0.0f;
	mMax = hasParam("max") ? getParam<float>("max") : 1.0f;
	mPressed = hasParam("pressed") ? getParam<bool>("pressed") : false;
	mStateless = hasParam("stateless") ? getParam<bool>("stateless") : true;
	mExclusive = hasParam("exclusive") ? getParam<bool>("exclusive") : false;
	mCallbackOnRelease = hasParam("callbackOnRelease") ? getParam<bool>("callbackOnRelease") : true;
	mContinuous = hasParam("continuous") ? getParam<bool>("continuous") : false;

	// set size
	int x = hasParam("width") ? getParam<int>("width") : MovingGraph::DEFAULT_WIDTH;
	int y = hasParam("height") ? getParam<int>("height") : MovingGraph::DEFAULT_HEIGHT;
	setSize(Vec2i(x, y));

	// set position and bounds
	setPositionAndBounds();
	mScreenMin = mBounds.getX1();
	mScreenMax = mBounds.getX2();

	mBufferSize = 128;
	mScale = mBounds.getHeight() * 0.5f;
	mInc = mBounds.getWidth() / ((float)mBufferSize - 1.0f);

	renderNameTexture();
	// set screen value
	update();
}

// without event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
    init();
}

// with event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
	: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
	// initialize unique variables
	addEventHandler(aEventHandler);

    init();
}

// without event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aParamString));
}

// with event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aEventHandler, aParamString));
}

void MovingGraph::draw()
{
	// set the color
	if (isActive()) {
		gl::color(UIController::ACTIVE_STROKE_COLOR);
	}
	else if (mPressed) {
		gl::color(UIController::DEFAULT_STROKE_COLOR);
	}
	else {
		gl::color(getBackgroundColor());
	}
	// draw the button background
	gl::drawSolidRect(getBounds());

	// draw the background
	drawBackground();

	// draw the graph
	if (isActive()) {
		gl::color(UIController::ACTIVE_STROKE_COLOR);
	}
	else {
		gl::color(UIController::DEFAULT_STROKE_COLOR);
	}
	// draw the outer rect
	gl::drawStrokedRect(getBounds());

	gl::pushMatrices();
	gl::translate( mBounds.getX1(), mBounds.getY1() + mScale );

	// active color for moving graph
	gl::color(UIController::ACTIVE_STROKE_COLOR);
	mShape.clear();
	mShape.moveTo( 0.0f, lmap<float>( mBuffer[0], mMin, mMax, mScale, -mScale ) );
	for (int i = 1; i < mBuffer.size(); i++)
	{
		mShape.lineTo( mInc * (float)i, lmap<float>( mBuffer[i], mMin, mMax, mScale, -mScale ) );
	}
	gl::draw( mShape );
	gl::popMatrices();
	// draw the label
	drawLabel();
}
void MovingGraph::release()
{
	if (mPressed) {
		mPressed = false;
		if (mCallbackOnRelease) {
			callEventHandlers();
		}
	}
}

void MovingGraph::handleMouseUp(const Vec2i &aMousePos)
{
	if (mStateless) {
		// mPressed should always be false if it's a stateless button; just call the handler
		callEventHandlers();

	}
	else {
		if (mPressed) {
			// if the button is in an exclusive group and it's already pressed, don't do anything
			if (!mExclusive) {
				// release the button
				mPressed = false;
				callEventHandlers();
			}
		}
		else {
			// if the button is an exclusive group and isn't pressed, release all the buttons in the group first
			if (mExclusive) {
				getParent()->releaseGroup(getGroup());
			}
			// press the button
			mPressed = true;
			callEventHandlers();
		}
	}
}

void MovingGraph::addEventHandler(const std::function<void(bool)>& aEventHandler)
{
	mEventHandlers.push_back(aEventHandler);
}

void MovingGraph::callEventHandlers()
{
	for (int i = 0; i < mEventHandlers.size(); i++) {
		mEventHandlers[i](mPressed);
	}
}

void MovingGraph::update()
{
	if (mContinuous && mStateless && isActive()) {
		callEventHandlers();
	}
	mBuffer.push_back( *mLinkedValue );

	if( mBuffer.size() >= mBufferSize )
	{
		mBuffer.erase( mBuffer.begin(), mBuffer.begin() + 1 );
	}
}
<commit_msg>if there aren't any event handlers it isn't acting like a button, so we don't change how it's drawn<commit_after>/*
 Adapted from ciUI's Moving Graph by @brucelane with permission from @rezaali
 https://github.com/rezaali/ciUI
*/

#include "Graph.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace MinimalUI;

int MovingGraph::DEFAULT_HEIGHT = UIElement::DEFAULT_HEIGHT;
int MovingGraph::DEFAULT_WIDTH = 96;

// common initialization
void MovingGraph::init()
{
	// initialize unique variables
	mMin = hasParam("min") ? getParam<float>("min") : 0.0f;
	mMax = hasParam("max") ? getParam<float>("max") : 1.0f;
	mPressed = hasParam("pressed") ? getParam<bool>("pressed") : false;
	mStateless = hasParam("stateless") ? getParam<bool>("stateless") : true;
	mExclusive = hasParam("exclusive") ? getParam<bool>("exclusive") : false;
	mCallbackOnRelease = hasParam("callbackOnRelease") ? getParam<bool>("callbackOnRelease") : true;
	mContinuous = hasParam("continuous") ? getParam<bool>("continuous") : false;

	// set size
	int x = hasParam("width") ? getParam<int>("width") : MovingGraph::DEFAULT_WIDTH;
	int y = hasParam("height") ? getParam<int>("height") : MovingGraph::DEFAULT_HEIGHT;
	setSize(Vec2i(x, y));

	// set position and bounds
	setPositionAndBounds();
	mScreenMin = mBounds.getX1();
	mScreenMax = mBounds.getX2();

	mBufferSize = 128;
	mScale = mBounds.getHeight() * 0.5f;
	mInc = mBounds.getWidth() / ((float)mBufferSize - 1.0f);

	renderNameTexture();
	// set screen value
	update();
}

// without event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
    init();
}

// with event handler
MovingGraph::MovingGraph(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
	: UIElement(aUIController, aName, aParamString), mLinkedValue(aValueToLink)
{
	// initialize unique variables
	addEventHandler(aEventHandler);

    init();
}

// without event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aParamString));
}

// with event handler
UIElementRef MovingGraph::create(UIController *aUIController, const string &aName, float *aValueToLink, const std::function<void(bool)>& aEventHandler, const string &aParamString)
{
	return shared_ptr<MovingGraph>(new MovingGraph(aUIController, aName, aValueToLink, aEventHandler, aParamString));
}

void MovingGraph::draw()
{
	// set the color
	if ( isActive() && mEventHandlers.size() > 0 ) {
		gl::color(UIController::ACTIVE_STROKE_COLOR);
	}
	else if (mPressed) {
		gl::color(UIController::DEFAULT_STROKE_COLOR);
	}
	else {
		gl::color(getBackgroundColor());
	}
	// draw the button background
	gl::drawSolidRect(getBounds());

	// draw the background
	drawBackground();

	// draw the graph
	if ( isActive() && mEventHandlers.size() > 0 ) {
		gl::color(UIController::ACTIVE_STROKE_COLOR);
	}
	else {
		gl::color(UIController::DEFAULT_STROKE_COLOR);
	}
	// draw the outer rect
	gl::drawStrokedRect(getBounds());

	gl::pushMatrices();
	gl::translate( mBounds.getX1(), mBounds.getY1() + mScale );

	// active color for moving graph
	gl::color(UIController::ACTIVE_STROKE_COLOR);
	mShape.clear();
	mShape.moveTo( 0.0f, lmap<float>( mBuffer[0], mMin, mMax, mScale, -mScale ) );
	for (int i = 1; i < mBuffer.size(); i++)
	{
		mShape.lineTo( mInc * (float)i, lmap<float>( mBuffer[i], mMin, mMax, mScale, -mScale ) );
	}
	gl::draw( mShape );
	gl::popMatrices();
	// draw the label
	drawLabel();
}
void MovingGraph::release()
{
	if (mPressed) {
		mPressed = false;
		if (mCallbackOnRelease) {
			callEventHandlers();
		}
	}
}

void MovingGraph::handleMouseUp(const Vec2i &aMousePos)
{
    if ( mEventHandlers.size() == 0 )
        return;

	if (mStateless) {
		// mPressed should always be false if it's a stateless button; just call the handler
		callEventHandlers();

	}
	else {
		if (mPressed) {
			// if the button is in an exclusive group and it's already pressed, don't do anything
			if (!mExclusive) {
				// release the button
				mPressed = false;
				callEventHandlers();
			}
		}
		else {
			// if the button is an exclusive group and isn't pressed, release all the buttons in the group first
			if (mExclusive) {
				getParent()->releaseGroup(getGroup());
			}
			// press the button
			mPressed = true;
			callEventHandlers();
		}
	}
}

void MovingGraph::addEventHandler(const std::function<void(bool)>& aEventHandler)
{
	mEventHandlers.push_back(aEventHandler);
}

void MovingGraph::callEventHandlers()
{
	for (int i = 0; i < mEventHandlers.size(); i++) {
		mEventHandlers[i](mPressed);
	}
}

void MovingGraph::update()
{
	if (mContinuous && mStateless && isActive()) {
		callEventHandlers();
	}
	mBuffer.push_back( *mLinkedValue );

	if( mBuffer.size() >= mBufferSize )
	{
		mBuffer.erase( mBuffer.begin(), mBuffer.begin() + 1 );
	}
}
<|endoftext|>


<commit_before>/*!
 * \file painter_dashed_stroke_params.cpp
 * \brief file painter_dashed_stroke_params.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <fastuidraw/painter/painter_dashed_stroke_params.hpp>
#include <fastuidraw/painter/painter_attribute_data_filler_path_stroked.hpp>
#include <fastuidraw/stroked_path.hpp>
#include <fastuidraw/util/pixel_distance_math.hpp>
#include "../private/util_private.hpp"

namespace
{

  class PainterDashedStrokeParamsData:public fastuidraw::PainterShaderData::DataBase
  {
  public:
    PainterDashedStrokeParamsData(void);

    virtual
    fastuidraw::PainterShaderData::DataBase*
    copy(void) const;

    virtual
    unsigned int
    data_size(unsigned int alignment) const;

    virtual
    void
    pack_data(unsigned int alignment, fastuidraw::c_array<fastuidraw::generic_data> dst) const;

    float m_miter_limit;
    float m_width;
    float m_dash_offset;
    float m_total_length;
    float m_first_interval_start;
    std::vector<fastuidraw::PainterDashedStrokeParams::DashPatternElement> m_dash_pattern;
    std::vector<fastuidraw::generic_data> m_dash_pattern_packed;
  };

  class DashEvaluator:public fastuidraw::DashEvaluatorBase
  {
  public:
    explicit
    DashEvaluator(bool pixel_width_stroking):
      m_pixel_width_stroking(pixel_width_stroking)
    {}

    virtual
    bool
    covered_by_dash_pattern(const fastuidraw::PainterShaderData::DataBase *data,
                            const fastuidraw::PainterAttribute &attrib) const;

    static
    bool
    close_to_boundary(float dist,
                      fastuidraw::range_type<float> interval);

    bool m_pixel_width_stroking;
  };
}
//////////////////////////////////////
// PainterDashedStrokeParamsData methods
PainterDashedStrokeParamsData::
PainterDashedStrokeParamsData(void):
  m_miter_limit(15.0f),
  m_width(2.0f),
  m_dash_offset(0.0f),
  m_total_length(0.0f),
  m_first_interval_start(0.0f)
{}

fastuidraw::PainterShaderData::DataBase*
PainterDashedStrokeParamsData::
copy(void) const
{
  return FASTUIDRAWnew PainterDashedStrokeParamsData(*this);
}

unsigned int
PainterDashedStrokeParamsData::
data_size(unsigned int alignment) const
{
  using namespace fastuidraw;
  return round_up_to_multiple(PainterDashedStrokeParams::stroke_static_data_size, alignment)
    + round_up_to_multiple(2 * m_dash_pattern.size(), alignment);
}

void
PainterDashedStrokeParamsData::
pack_data(unsigned int alignment, fastuidraw::c_array<fastuidraw::generic_data> dst) const
{
  using namespace fastuidraw;

  dst[PainterDashedStrokeParams::stroke_miter_limit_offset].f = m_miter_limit;
  dst[PainterDashedStrokeParams::stroke_width_offset].f = m_width;
  dst[PainterDashedStrokeParams::stroke_dash_offset_offset].f = m_dash_offset;
  dst[PainterDashedStrokeParams::stroke_total_length_offset].f = m_total_length;
  dst[PainterDashedStrokeParams::stroke_first_interval_start_offset].f = m_first_interval_start;
  dst[PainterDashedStrokeParams::stroke_number_intervals_offset].u = m_dash_pattern_packed.size();

  if(!m_dash_pattern_packed.empty())
    {
      c_array<generic_data> dst_pattern;
      dst_pattern = dst.sub_array(round_up_to_multiple(PainterDashedStrokeParams::stroke_static_data_size, alignment));
      std::copy(m_dash_pattern_packed.begin(), m_dash_pattern_packed.end(), dst_pattern.begin());
      for(unsigned int i = m_dash_pattern_packed.size(), endi = dst_pattern.size(); i < endi; ++i)
        {
          //make the last entry larger than the total length so a
          //shader can use that to know when it has reached the end.
          dst_pattern[i].f = m_total_length * 2.0f + 1.0f;
        }
    }
}

///////////////////////////////
// DashEvaluator methods
bool
DashEvaluator::
covered_by_dash_pattern(const fastuidraw::PainterShaderData::DataBase *data,
                        const fastuidraw::PainterAttribute &attrib) const
{
  const PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<const PainterDashedStrokeParamsData*>(data) != NULL);
  d = static_cast<const PainterDashedStrokeParamsData*>(data);

  if(d->m_total_length <= 0.0f)
    {
      return false;
    }

  float fd, ff, dist, distance;
  fastuidraw::range_type<float> interval;
  bool return_value(true);

  /* PainterDashedStrokeParams is for attributes packed
     by PainterAttributeDataFillerPathStroked which
     stores the distance from the contour start at
     m_attrib1.y packed as a float
   */
  distance = fastuidraw::unpack_float(attrib.m_attrib1.y()) + d->m_dash_offset;
  fd = std::floor(distance / d->m_total_length);
  ff = d->m_total_length * fd;
  dist = distance - ff;

  for(unsigned int i = 0, endi = d->m_dash_pattern_packed.size(); i < endi; ++i)
    {
      float v;

      v = d->m_dash_pattern_packed[i].f;
      if(dist < v)
        {
          interval.m_begin = ff;
          interval.m_end = ff + v;
          /* if the boundary is too close we will return false
             even if we are in the draw interval so that we can
             avoid bad rendering.
           */
          return return_value && !close_to_boundary(dist, interval);
        }
      return_value = !return_value;
    }
  return false;
}

bool
DashEvaluator::
close_to_boundary(float dist, fastuidraw::range_type<float> interval)
{
  bool return_value;

  return_value = interval.m_begin == dist || interval.m_end == dist;
  return return_value;
}

///////////////////////////////////
// fastuidraw::PainterDashedStrokeParams methods
fastuidraw::PainterDashedStrokeParams::
PainterDashedStrokeParams(void)
{
  m_data = FASTUIDRAWnew PainterDashedStrokeParamsData();
}

float
fastuidraw::PainterDashedStrokeParams::
miter_limit(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_miter_limit;
}

float
fastuidraw::PainterDashedStrokeParams::
width(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_miter_limit;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
miter_limit(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_miter_limit = f;
  return *this;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
width(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_width = f;
  return *this;
}

float
fastuidraw::PainterDashedStrokeParams::
dash_offset(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_dash_offset;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
dash_offset(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_dash_offset = f;
  return *this;
}

fastuidraw::const_c_array<fastuidraw::PainterDashedStrokeParams::DashPatternElement>
fastuidraw::PainterDashedStrokeParams::
dash_pattern(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return make_c_array(d->m_dash_pattern);
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
dash_pattern(const_c_array<DashPatternElement> f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);

  /* skip to first element on f[] that is non-zero.
   */
  while(f.front().m_draw_length <= 0.0f && f.front().m_space_length <= 0.0f)
    {
      f = f.sub_array(1);
    }

  d->m_dash_pattern.resize(f.size());
  if(d->m_dash_pattern.empty())
    {
      return *this;
    }

  /* santize the dash pattern:
       - starting draw length can be 0
       - any other 0 lengths are to be joined
   */
  unsigned int current_write(0);

  d->m_dash_pattern[current_write].m_draw_length = std::max(0.0f, f[0].m_draw_length);
  d->m_dash_pattern[current_write].m_space_length = std::max(0.0f, f[0].m_space_length);
  for(unsigned int i = 1, endi = f.size(); i < endi; ++i)
    {
      /* things to do:
           - if d->m_dash_pattern[current_write].m_space_length is 0,
             then we join it with the element we are on by adding the
             draw lengths.
           - if f[i] has draw length 0 we join it's skip with
             d->m_dash_pattern[current_write]
       */
      if(d->m_dash_pattern[current_write].m_space_length <= 0.0f)
        {
          d->m_dash_pattern[current_write].m_draw_length += std::max(0.0f, f[i].m_draw_length);
          d->m_dash_pattern[current_write].m_space_length = std::max(0.0f, f[i].m_space_length);
        }
      else if(f[i].m_draw_length <= 0.0f)
        {
          d->m_dash_pattern[current_write].m_space_length += std::max(0.0f, f[i].m_space_length);
        }
      else
        {
          ++current_write;
          d->m_dash_pattern[current_write].m_draw_length = std::max(0.0f, f[i].m_draw_length);
          d->m_dash_pattern[current_write].m_space_length = std::max(0.0f, f[i].m_space_length);
        }
    }

  d->m_dash_pattern.resize(current_write + 1);

  d->m_total_length = 0.0f;
  for(unsigned int i = 0, endi = current_write + 1; i < endi; ++i)
    {
      d->m_total_length += d->m_dash_pattern[i].m_draw_length;
      d->m_total_length += d->m_dash_pattern[i].m_space_length;
    }

  if(d->m_dash_pattern.back().m_space_length <= 0.0f && d->m_dash_pattern.front().m_draw_length > 0.0f)
    {
      d->m_first_interval_start = -d->m_dash_pattern.back().m_draw_length;
    }
  else if(d->m_dash_pattern.back().m_space_length > 0.0f && d->m_dash_pattern.front().m_draw_length <= 0.0f)
    {
      d->m_first_interval_start = -d->m_dash_pattern.back().m_space_length;
    }
  else
    {
      d->m_first_interval_start = 0.0f;
    }

  d->m_dash_pattern_packed.resize(d->m_dash_pattern.size() * 2);
  if(!d->m_dash_pattern_packed.empty())
    {
      float total_length = 0.0f;
      for(unsigned int i = 0, j = 0, endi = d->m_dash_pattern.size(); i < endi; ++i, j += 2)
        {
          total_length += d->m_dash_pattern[i].m_draw_length;
          d->m_dash_pattern_packed[j].f = total_length;

          total_length += d->m_dash_pattern[i].m_space_length;
          d->m_dash_pattern_packed[j + 1].f = total_length;
        }
    }

  return *this;
}

fastuidraw::reference_counted_ptr<const fastuidraw::DashEvaluatorBase>
fastuidraw::PainterDashedStrokeParams::
dash_evaluator(bool pixel_width_stroking)
{
  return FASTUIDRAWnew DashEvaluator(pixel_width_stroking);
}
<commit_msg>fastuidraw/painter: observe 0-length draw lengths in dash patterns to get dotting<commit_after>/*!
 * \file painter_dashed_stroke_params.cpp
 * \brief file painter_dashed_stroke_params.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <fastuidraw/painter/painter_dashed_stroke_params.hpp>
#include <fastuidraw/painter/painter_attribute_data_filler_path_stroked.hpp>
#include <fastuidraw/stroked_path.hpp>
#include <fastuidraw/util/pixel_distance_math.hpp>
#include "../private/util_private.hpp"

namespace
{

  class PainterDashedStrokeParamsData:public fastuidraw::PainterShaderData::DataBase
  {
  public:
    PainterDashedStrokeParamsData(void);

    virtual
    fastuidraw::PainterShaderData::DataBase*
    copy(void) const;

    virtual
    unsigned int
    data_size(unsigned int alignment) const;

    virtual
    void
    pack_data(unsigned int alignment, fastuidraw::c_array<fastuidraw::generic_data> dst) const;

    float m_miter_limit;
    float m_width;
    float m_dash_offset;
    float m_total_length;
    float m_first_interval_start;
    std::vector<fastuidraw::PainterDashedStrokeParams::DashPatternElement> m_dash_pattern;
    std::vector<fastuidraw::generic_data> m_dash_pattern_packed;
  };

  class DashEvaluator:public fastuidraw::DashEvaluatorBase
  {
  public:
    explicit
    DashEvaluator(bool pixel_width_stroking):
      m_pixel_width_stroking(pixel_width_stroking)
    {}

    virtual
    bool
    covered_by_dash_pattern(const fastuidraw::PainterShaderData::DataBase *data,
                            const fastuidraw::PainterAttribute &attrib) const;

    static
    bool
    close_to_boundary(float dist,
                      fastuidraw::range_type<float> interval);

    bool m_pixel_width_stroking;
  };
}
//////////////////////////////////////
// PainterDashedStrokeParamsData methods
PainterDashedStrokeParamsData::
PainterDashedStrokeParamsData(void):
  m_miter_limit(15.0f),
  m_width(2.0f),
  m_dash_offset(0.0f),
  m_total_length(0.0f),
  m_first_interval_start(0.0f)
{}

fastuidraw::PainterShaderData::DataBase*
PainterDashedStrokeParamsData::
copy(void) const
{
  return FASTUIDRAWnew PainterDashedStrokeParamsData(*this);
}

unsigned int
PainterDashedStrokeParamsData::
data_size(unsigned int alignment) const
{
  using namespace fastuidraw;
  return round_up_to_multiple(PainterDashedStrokeParams::stroke_static_data_size, alignment)
    + round_up_to_multiple(2 * m_dash_pattern.size(), alignment);
}

void
PainterDashedStrokeParamsData::
pack_data(unsigned int alignment, fastuidraw::c_array<fastuidraw::generic_data> dst) const
{
  using namespace fastuidraw;

  dst[PainterDashedStrokeParams::stroke_miter_limit_offset].f = m_miter_limit;
  dst[PainterDashedStrokeParams::stroke_width_offset].f = m_width;
  dst[PainterDashedStrokeParams::stroke_dash_offset_offset].f = m_dash_offset;
  dst[PainterDashedStrokeParams::stroke_total_length_offset].f = m_total_length;
  dst[PainterDashedStrokeParams::stroke_first_interval_start_offset].f = m_first_interval_start;
  dst[PainterDashedStrokeParams::stroke_number_intervals_offset].u = m_dash_pattern_packed.size();

  if(!m_dash_pattern_packed.empty())
    {
      c_array<generic_data> dst_pattern;
      dst_pattern = dst.sub_array(round_up_to_multiple(PainterDashedStrokeParams::stroke_static_data_size, alignment));
      std::copy(m_dash_pattern_packed.begin(), m_dash_pattern_packed.end(), dst_pattern.begin());
      for(unsigned int i = m_dash_pattern_packed.size(), endi = dst_pattern.size(); i < endi; ++i)
        {
          //make the last entry larger than the total length so a
          //shader can use that to know when it has reached the end.
          dst_pattern[i].f = m_total_length * 2.0f + 1.0f;
        }
    }
}

///////////////////////////////
// DashEvaluator methods
bool
DashEvaluator::
covered_by_dash_pattern(const fastuidraw::PainterShaderData::DataBase *data,
                        const fastuidraw::PainterAttribute &attrib) const
{
  const PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<const PainterDashedStrokeParamsData*>(data) != NULL);
  d = static_cast<const PainterDashedStrokeParamsData*>(data);

  if(d->m_total_length <= 0.0f)
    {
      return false;
    }

  float fd, ff, dist, distance;
  fastuidraw::range_type<float> interval;
  bool return_value(true);

  /* PainterDashedStrokeParams is for attributes packed
     by PainterAttributeDataFillerPathStroked which
     stores the distance from the contour start at
     m_attrib1.y packed as a float
   */
  distance = fastuidraw::unpack_float(attrib.m_attrib1.y()) + d->m_dash_offset;
  fd = std::floor(distance / d->m_total_length);
  ff = d->m_total_length * fd;
  dist = distance - ff;

  for(unsigned int i = 0, endi = d->m_dash_pattern_packed.size(); i < endi; ++i)
    {
      float v;

      v = d->m_dash_pattern_packed[i].f;
      if(dist < v)
        {
          interval.m_begin = ff;
          interval.m_end = ff + v;
          /* if the boundary is too close we will return false
             even if we are in the draw interval so that we can
             avoid bad rendering.
           */
          return return_value && !close_to_boundary(dist, interval);
        }
      return_value = !return_value;
    }
  return false;
}

bool
DashEvaluator::
close_to_boundary(float dist, fastuidraw::range_type<float> interval)
{
  bool return_value;

  return_value = interval.m_begin == dist || interval.m_end == dist;
  return return_value;
}

///////////////////////////////////
// fastuidraw::PainterDashedStrokeParams methods
fastuidraw::PainterDashedStrokeParams::
PainterDashedStrokeParams(void)
{
  m_data = FASTUIDRAWnew PainterDashedStrokeParamsData();
}

float
fastuidraw::PainterDashedStrokeParams::
miter_limit(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_miter_limit;
}

float
fastuidraw::PainterDashedStrokeParams::
width(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_miter_limit;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
miter_limit(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_miter_limit = f;
  return *this;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
width(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_width = f;
  return *this;
}

float
fastuidraw::PainterDashedStrokeParams::
dash_offset(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return d->m_dash_offset;
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
dash_offset(float f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  d->m_dash_offset = f;
  return *this;
}

fastuidraw::const_c_array<fastuidraw::PainterDashedStrokeParams::DashPatternElement>
fastuidraw::PainterDashedStrokeParams::
dash_pattern(void) const
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);
  return make_c_array(d->m_dash_pattern);
}

fastuidraw::PainterDashedStrokeParams&
fastuidraw::PainterDashedStrokeParams::
dash_pattern(const_c_array<DashPatternElement> f)
{
  PainterDashedStrokeParamsData *d;
  assert(dynamic_cast<PainterDashedStrokeParamsData*>(m_data) != NULL);
  d = static_cast<PainterDashedStrokeParamsData*>(m_data);

  /* skip to first element on f[] that is non-zero.
   */
  while(f.front().m_draw_length <= 0.0f && f.front().m_space_length <= 0.0f)
    {
      f = f.sub_array(1);
    }

  d->m_dash_pattern.resize(f.size());
  if(d->m_dash_pattern.empty())
    {
      return *this;
    }

  /* santize the dash pattern:
       - starting draw length can be 0
       - any other 0 lengths are to be joined
   */
  unsigned int current_write(0);

  d->m_dash_pattern[current_write].m_draw_length = std::max(0.0f, f[0].m_draw_length);
  d->m_dash_pattern[current_write].m_space_length = std::max(0.0f, f[0].m_space_length);
  for(unsigned int i = 1, endi = f.size(); i < endi; ++i)
    {
      /* things to do:
           - if d->m_dash_pattern[current_write].m_space_length is 0,
             then we join it with the element we are on by adding the
             draw lengths.
       */
      if(d->m_dash_pattern[current_write].m_space_length <= 0.0f)
        {
          d->m_dash_pattern[current_write].m_draw_length += std::max(0.0f, f[i].m_draw_length);
        }
      else
        {
          ++current_write;
          d->m_dash_pattern[current_write].m_draw_length = std::max(0.0f, f[i].m_draw_length);
          d->m_dash_pattern[current_write].m_space_length = std::max(0.0f, f[i].m_space_length);
        }
    }

  d->m_dash_pattern.resize(current_write + 1);

  d->m_total_length = 0.0f;
  for(unsigned int i = 0, endi = current_write + 1; i < endi; ++i)
    {
      d->m_total_length += d->m_dash_pattern[i].m_draw_length;
      d->m_total_length += d->m_dash_pattern[i].m_space_length;
    }

  if(d->m_dash_pattern.back().m_space_length <= 0.0f && d->m_dash_pattern.front().m_draw_length > 0.0f)
    {
      d->m_first_interval_start = -d->m_dash_pattern.back().m_draw_length;
    }
  else
    {
      d->m_first_interval_start = 0.0f;
    }

  d->m_dash_pattern_packed.resize(d->m_dash_pattern.size() * 2);
  if(!d->m_dash_pattern_packed.empty())
    {
      float total_length = 0.0f;
      for(unsigned int i = 0, j = 0, endi = d->m_dash_pattern.size(); i < endi; ++i, j += 2)
        {
          total_length += d->m_dash_pattern[i].m_draw_length;
          d->m_dash_pattern_packed[j].f = total_length;

          total_length += d->m_dash_pattern[i].m_space_length;
          d->m_dash_pattern_packed[j + 1].f = total_length;
        }
    }

  return *this;
}

fastuidraw::reference_counted_ptr<const fastuidraw::DashEvaluatorBase>
fastuidraw::PainterDashedStrokeParams::
dash_evaluator(bool pixel_width_stroking)
{
  return FASTUIDRAWnew DashEvaluator(pixel_width_stroking);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 the author 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 "libtorrent/http_connection.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

	enum { max_bottled_buffer = 1024 * 1024 };

void http_connection::get(std::string const& url, time_duration timeout
	, bool handle_redirect)
{
	m_redirect = handle_redirect;
	std::string protocol;
	std::string auth;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"\r\nConnection: close\r\n";
	if (!auth.empty())
		headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
	headers << "\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout, bool handle_redirect)
{
	m_redirect = handle_redirect;
	m_timeout = timeout;
	m_timer.expires_from_now(m_timeout);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		m_sock.close();
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_connect_timeout()
{
	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	if (m_bottled && m_called) return;
	m_called = true;
	m_handler(asio::error::timed_out, m_parser, 0, 0);
	close();
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
	c->m_connection_ticket = -1;

	if (e == asio::error::operation_aborted) return;

	if (c->m_bottled && c->m_called) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->m_called = true;
		c->m_handler(asio::error::timed_out, c->m_parser, 0, 0);
		return;
	}

	c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	m_timer.cancel();
	m_limiter_timer.cancel();
	m_sock.close();
	m_hostname.clear();
	m_port.clear();

	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}
	TORRENT_ASSERT(i != tcp::resolver::iterator());
	m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
		, bind(&http_connection::on_connect_timeout, shared_from_this())
		, m_timeout);
}

void http_connection::connect(int ticket, tcp::endpoint target_address)
{
	m_connection_ticket = ticket;
	m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		if (m_connect_handler) m_connect_handler(*this);
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
			, bind(&http_connection::on_connect_timeout, shared_from_this())
			, m_timeout);
	}
*/	else
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		TORRENT_ASSERT(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		char const* data = 0;
		std::size_t size = 0;
		if (m_bottled && m_parser.header_finished())
		{
			data = m_parser.get_body().begin;
			size = m_parser.get_body().left();
		}
		m_handler(e, m_parser, data, size);
		return;
	}

	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	m_read_pos += bytes_transferred;
	TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size()));

	// having a nonempty path means we should handle redirects
	if (m_redirect && m_parser.header_finished())
	{
		int code = m_parser.status_code();
		if (code >= 300 && code < 400)
		{
			// attempt a redirect
			std::string const& url = m_parser.header("location");
			if (url.empty())
			{
				// missing location header
				if (m_bottled && m_called) return;
				m_called = true;
				m_handler(e, m_parser, 0, 0);
				return;
			}

			m_limiter_timer_active = false;
			close();

			get(url, m_timeout);
			return;
		}

		m_redirect = false;
	}

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		m_parser.incoming(rcv_buf);
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			m_timer.cancel();
			if (m_bottled && m_called) return;
			m_called = true;
			m_handler(e, m_parser, m_parser.get_body().begin, m_parser.get_body().left());
		}
	}
	else
	{
		TORRENT_ASSERT(!m_bottled);
		m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer)));
	if (m_read_pos == max_bottled_buffer)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error::eof, m_parser, 0, 0);
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		if (!m_bottled || !m_called)
			m_handler(e, m_parser, 0, 0);
		return;
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250));
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_limiter_timer_active)
	{
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250));
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<commit_msg>http_connection shutdown fixes<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 the author 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 "libtorrent/http_connection.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

	enum { max_bottled_buffer = 1024 * 1024 };

void http_connection::get(std::string const& url, time_duration timeout
	, bool handle_redirect)
{
	m_redirect = handle_redirect;
	std::string protocol;
	std::string auth;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"\r\nConnection: close\r\n";
	if (!auth.empty())
		headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
	headers << "\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout, bool handle_redirect)
{
	m_redirect = handle_redirect;
	m_timeout = timeout;
	m_timer.expires_from_now(m_timeout);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		m_sock.close();
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_connect_timeout()
{
	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	if (m_bottled && m_called) return;
	m_called = true;
	m_handler(asio::error::timed_out, m_parser, 0, 0);
	close();
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
	c->m_connection_ticket = -1;

	if (e == asio::error::operation_aborted) return;

	if (c->m_bottled && c->m_called) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->m_called = true;
		c->m_handler(asio::error::timed_out, c->m_parser, 0, 0);
		return;
	}

	if (!c->m_sock.is_open()) return;

	c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	m_timer.cancel();
	m_limiter_timer.cancel();
	m_sock.close();
	m_hostname.clear();
	m_port.clear();

	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	if (m_called) return;
	m_called = true;
	m_handler(asio::error::operation_aborted, m_parser, 0, 0);
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}
	TORRENT_ASSERT(i != tcp::resolver::iterator());
	m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
		, bind(&http_connection::on_connect_timeout, shared_from_this())
		, m_timeout);
}

void http_connection::connect(int ticket, tcp::endpoint target_address)
{
	m_connection_ticket = ticket;
	m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		if (m_connect_handler) m_connect_handler(*this);
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
			, bind(&http_connection::on_connect_timeout, shared_from_this())
			, m_timeout);
	}
*/	else
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		TORRENT_ASSERT(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		char const* data = 0;
		std::size_t size = 0;
		if (m_bottled && m_parser.header_finished())
		{
			data = m_parser.get_body().begin;
			size = m_parser.get_body().left();
		}
		m_handler(e, m_parser, data, size);
		return;
	}

	if (e)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(e, m_parser, 0, 0);
		return;
	}

	m_read_pos += bytes_transferred;
	TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size()));

	// having a nonempty path means we should handle redirects
	if (m_redirect && m_parser.header_finished())
	{
		int code = m_parser.status_code();
		if (code >= 300 && code < 400)
		{
			// attempt a redirect
			std::string const& url = m_parser.header("location");
			if (url.empty())
			{
				// missing location header
				if (m_bottled && m_called) return;
				m_called = true;
				m_handler(e, m_parser, 0, 0);
				return;
			}

			m_limiter_timer_active = false;
			close();

			get(url, m_timeout);
			return;
		}

		m_redirect = false;
	}

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		m_parser.incoming(rcv_buf);
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			m_timer.cancel();
			if (m_bottled && m_called) return;
			m_called = true;
			m_handler(e, m_parser, m_parser.get_body().begin, m_parser.get_body().left());
		}
	}
	else
	{
		TORRENT_ASSERT(!m_bottled);
		m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer)));
	if (m_read_pos == max_bottled_buffer)
	{
		close();
		if (m_bottled && m_called) return;
		m_called = true;
		m_handler(asio::error::eof, m_parser, 0, 0);
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		if (!m_bottled || !m_called)
			m_handler(e, m_parser, 0, 0);
		return;
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	if (!m_sock.is_open()) return;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250));
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_sock.is_open()) return;

	if (!m_limiter_timer_active)
	{
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250));
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 * transaction.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include "backend/concurrency/transaction.h"

#include "backend/common/synch.h"
#include "backend/common/logger.h"

#include <chrono>
#include <thread>
#include <iomanip>

namespace peloton {
namespace concurrency {

void Transaction::RecordInsert(ItemPointer location) {
    auto& manager = catalog::Manager::GetInstance();
    storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.locator[location.block]);
    inserted_tuples[tile_group].push_back(location.offset);
}

void Transaction::RecordDelete(ItemPointer location) {
    auto& manager = catalog::Manager::GetInstance();
    storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.locator[location.block]);
    deleted_tuples[tile_group].push_back(location.offset);
}

bool Transaction::HasInsertedTuples(storage::TileGroup* tile_group) const {
    auto tile_group_itr = inserted_tuples.find(tile_group);
    if(tile_group_itr != inserted_tuples.end() && !tile_group_itr->second.empty())
        return true;

    return false;
}

bool Transaction::HasDeletedTuples(storage::TileGroup* tile_group) const {
    auto tile_group_itr = deleted_tuples.find(tile_group);
    if(tile_group_itr != deleted_tuples.end() && !tile_group_itr->second.empty())
        return true;

    return false;
}

const std::map<storage::TileGroup*, std::vector<oid_t> >& Transaction::GetInsertedTuples() {
    return inserted_tuples;
}

const std::map<storage::TileGroup*, std::vector<oid_t> >& Transaction::GetDeletedTuples() {
    return deleted_tuples;
}

void Transaction::IncrementRefCount() {
    ++ref_count;
}

void Transaction::DecrementRefCount() {
    assert(ref_count > 0);

    // DROP transaction when ref count reaches 1
    if (ref_count.fetch_sub(1) == 1) {
        delete this;
    }
}

void Transaction::SetResult(Result result) {
  result_ = result;
}

Result Transaction::GetResult() const {
  return result_;
}

std::ostream& operator<<(std::ostream& os, const Transaction& txn) {

    os << "\tTxn :: @" <<  &txn << " ID : " << std::setw(4) << txn.txn_id
       << " Commit ID : " << std::setw(4) << txn.cid
       << " Last Commit ID : " << std::setw(4) << txn.last_cid
       << " Result : " << txn.result_;

    if(txn.next == nullptr) {
        os << " Next : " << std::setw(4) << txn.next;
    }
    else {
        os << " Next : " << std::setw(4) << txn.next->txn_id;
    }

    os << " Ref count : " << std::setw(4) << txn.ref_count <<  "\n";
    return os;
}

} // End concurrency namespace
} // End peloton namespace
<commit_msg>Disable check.<commit_after>/*-------------------------------------------------------------------------
 *
 * transaction.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include "backend/concurrency/transaction.h"

#include "backend/common/synch.h"
#include "backend/common/logger.h"

#include <chrono>
#include <thread>
#include <iomanip>

namespace peloton {
namespace concurrency {

void Transaction::RecordInsert(ItemPointer location) {
    auto& manager = catalog::Manager::GetInstance();
    storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.locator[location.block]);
    inserted_tuples[tile_group].push_back(location.offset);
}

void Transaction::RecordDelete(ItemPointer location) {
    auto& manager = catalog::Manager::GetInstance();
    storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.locator[location.block]);
    deleted_tuples[tile_group].push_back(location.offset);
}

bool Transaction::HasInsertedTuples(storage::TileGroup* tile_group) const {
    auto tile_group_itr = inserted_tuples.find(tile_group);
    if(tile_group_itr != inserted_tuples.end() && !tile_group_itr->second.empty())
        return true;

    return false;
}

bool Transaction::HasDeletedTuples(storage::TileGroup* tile_group) const {
    auto tile_group_itr = deleted_tuples.find(tile_group);
    if(tile_group_itr != deleted_tuples.end() && !tile_group_itr->second.empty())
        return true;

    return false;
}

const std::map<storage::TileGroup*, std::vector<oid_t> >& Transaction::GetInsertedTuples() {
    return inserted_tuples;
}

const std::map<storage::TileGroup*, std::vector<oid_t> >& Transaction::GetDeletedTuples() {
    return deleted_tuples;
}

void Transaction::IncrementRefCount() {
    ++ref_count;
}

void Transaction::DecrementRefCount() {
    // DROP transaction when ref count reaches 1
    if (ref_count.fetch_sub(1) == 1) {
        delete this;
    }
}

void Transaction::SetResult(Result result) {
  result_ = result;
}

Result Transaction::GetResult() const {
  return result_;
}

std::ostream& operator<<(std::ostream& os, const Transaction& txn) {

    os << "\tTxn :: @" <<  &txn << " ID : " << std::setw(4) << txn.txn_id
       << " Commit ID : " << std::setw(4) << txn.cid
       << " Last Commit ID : " << std::setw(4) << txn.last_cid
       << " Result : " << txn.result_;

    if(txn.next == nullptr) {
        os << " Next : " << std::setw(4) << txn.next;
    }
    else {
        os << " Next : " << std::setw(4) << txn.next->txn_id;
    }

    os << " Ref count : " << std::setw(4) << txn.ref_count <<  "\n";
    return os;
}

} // End concurrency namespace
} // End peloton namespace
<|endoftext|>