<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/CIFactory.h"

#include "ChainedConsumer.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {
  //
  //  Dummy function so we can use dladdr to find the executable path.
  //
  void locate_cling_executable()
  {
  }

  CompilerInstance* CIFactory::createCI(llvm::StringRef code,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    return createCI(llvm::MemoryBuffer::getMemBuffer(code),argc, argv, llvmdir);
  }

  CompilerInstance* CIFactory::createCI(llvm::MemoryBuffer* buffer,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir){
    // main's argv[0] is skipped!

    // Create an instance builder, passing the llvmdir and arguments.
    //
    //  Initialize the llvm library.
    //
    // If not set, exception handling will not be turned on
    llvm::JITExceptionHandling = true;
    llvm::InitializeNativeTarget();
    llvm::InitializeAllAsmPrinters();
    llvm::sys::Path resource_path;
    if (llvmdir) {
      resource_path = llvmdir;
      resource_path.appendComponent("lib");
      resource_path.appendComponent("clang");
      resource_path.appendComponent(CLANG_VERSION_STRING);
    } else {
      // FIXME: The first arg really does need to be argv[0] on FreeBSD.
      //
      // Note: The second arg is not used for Apple, FreeBSD, Linux,
      //       or cygwin, and can only be used on systems which support
      //       the use of dladdr().
      //
      // Note: On linux and cygwin this uses /proc/self/exe to find the path.
      //
      // Note: On Apple it uses _NSGetExecutablePath().
      //
      // Note: On FreeBSD it uses getprogpath().
      //
      // Note: Otherwise it uses dladdr().
      //
      resource_path = CompilerInvocation::GetResourcesPath("cling",
                                       (void*)(intptr_t) locate_cling_executable
                                                           );
    }

    // Create and setup a compiler instance.
    CompilerInstance* CI = new CompilerInstance();
    {
      //
      //  Buffer the error messages while we process
      //  the compiler options.
      //

      // Needed when we call CreateFromArgs
      CI->createDiagnostics(0, 0);
      CompilerInvocation::CreateFromArgs
        (CI->getInvocation(), argv, argv + argc, CI->getDiagnostics());

      // Reset the diagnostics options that came from CreateFromArgs
      DiagnosticOptions& DiagOpts = CI->getDiagnosticOpts();
      DiagOpts.ShowColors = 1;
      DiagnosticConsumer* Client = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
      CI->createDiagnostics(0, 0, Client);

      // Set the language options, which cling needs
      SetClingCustomLangOpts(CI->getLangOpts());

      if (CI->getHeaderSearchOpts().UseBuiltinIncludes &&
          CI->getHeaderSearchOpts().ResourceDir.empty()) {
        CI->getHeaderSearchOpts().ResourceDir = resource_path.str();
      }
      CI->getInvocation().getPreprocessorOpts().addMacroDef("__CLING__");
      if (CI->getDiagnostics().hasErrorOccurred()) {
        delete CI;
        CI = 0;
        return 0;
      }
    }
    CI->setTarget(TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
                                               CI->getTargetOpts()));
    if (!CI->hasTarget()) {
      delete CI;
      CI = 0;
      return 0;
    }
    CI->getTarget().setForcedLangOptions(CI->getLangOpts());
    SetClingTargetLangOpts(CI->getLangOpts(), CI->getTarget());

    // Set up source and file managers
    CI->createFileManager();
    CI->createSourceManager(CI->getFileManager());

    // Set up the memory buffer
    if (buffer)
      CI->getSourceManager().createMainFileIDForMemBuffer(buffer);

    // Set up the preprocessor
    CI->createPreprocessor();
    Preprocessor& PP = CI->getPreprocessor();
    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
                                           PP.getLangOptions());
    /*NoBuiltins = */ //true);

    // Set up the ASTContext
    ASTContext *Ctx = new ASTContext(CI->getLangOpts(),
                                     PP.getSourceManager(), &CI->getTarget(), PP.getIdentifierTable(),
                                     PP.getSelectorTable(), PP.getBuiltinInfo(), 0);
    CI->setASTContext(Ctx);
    //CI->getSourceManager().clearIDTables(); //do we really need it?

    // Set up the ASTConsumers
    CI->setASTConsumer(new ChainedConsumer());

    // Set up Sema
    CodeCompleteConsumer* CCC = 0;
    CI->createSema(TU_Prefix, CCC);

    // Set CodeGen options
    // CI->getCodeGenOpts().DebugInfo = 1; // want debug info
    // CI->getCodeGenOpts().EmitDeclMetadata = 1; // For unloading, for later
    CI->getCodeGenOpts().OptimizationLevel = 0; // see pure SSA, that comes out
    assert((CI->getCodeGenOpts().VerifyModule = 1) && "When asserts are on, let's also assert the module");
    return CI;
  }

  void CIFactory::SetClingCustomLangOpts(LangOptions& Opts) {
    Opts.EmitAllDecls = 1;
    Opts.ObjCNonFragileABI2 = 0;
    Opts.Exceptions = 1;
    Opts.CXXExceptions = 1;
    Opts.Deprecated = 1;
  }

  void CIFactory::SetClingTargetLangOpts(LangOptions& Opts,
                                         const TargetInfo& Target) {
    if (Target.getTriple().getOS() == llvm::Triple::Win32) {
      Opts.MicrosoftExt = 1;
      Opts.MSCVersion = 1300;
      // Should fix http://llvm.org/bugs/show_bug.cgi?id=10528
      Opts.DelayedTemplateParsing = 1;
    } else {
      Opts.MicrosoftExt = 0;
    }
    if (Target.getTriple().getArch() == llvm::Triple::x86) {
       Opts.ObjCNonFragileABI = 1;
    } else {
       Opts.ObjCNonFragileABI = 0;
    }
    if (Target.getTriple().isOSDarwin()) {
       Opts.NeXTRuntime = 1;
    } else {
       Opts.NeXTRuntime = 0;
    }
  }
} // end namespace
<commit_msg>Use == for comparison and obey 80 column rule<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/CIFactory.h"

#include "ChainedConsumer.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {
  //
  //  Dummy function so we can use dladdr to find the executable path.
  //
  void locate_cling_executable()
  {
  }

  CompilerInstance* CIFactory::createCI(llvm::StringRef code,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    return createCI(llvm::MemoryBuffer::getMemBuffer(code),argc, argv, llvmdir);
  }

  CompilerInstance* CIFactory::createCI(llvm::MemoryBuffer* buffer,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir){
    // main's argv[0] is skipped!

    // Create an instance builder, passing the llvmdir and arguments.
    //
    //  Initialize the llvm library.
    //
    // If not set, exception handling will not be turned on
    llvm::JITExceptionHandling = true;
    llvm::InitializeNativeTarget();
    llvm::InitializeAllAsmPrinters();
    llvm::sys::Path resource_path;
    if (llvmdir) {
      resource_path = llvmdir;
      resource_path.appendComponent("lib");
      resource_path.appendComponent("clang");
      resource_path.appendComponent(CLANG_VERSION_STRING);
    } else {
      // FIXME: The first arg really does need to be argv[0] on FreeBSD.
      //
      // Note: The second arg is not used for Apple, FreeBSD, Linux,
      //       or cygwin, and can only be used on systems which support
      //       the use of dladdr().
      //
      // Note: On linux and cygwin this uses /proc/self/exe to find the path.
      //
      // Note: On Apple it uses _NSGetExecutablePath().
      //
      // Note: On FreeBSD it uses getprogpath().
      //
      // Note: Otherwise it uses dladdr().
      //
      resource_path = CompilerInvocation::GetResourcesPath("cling",
                                       (void*)(intptr_t) locate_cling_executable
                                                           );
    }

    // Create and setup a compiler instance.
    CompilerInstance* CI = new CompilerInstance();
    {
      //
      //  Buffer the error messages while we process
      //  the compiler options.
      //

      // Needed when we call CreateFromArgs
      CI->createDiagnostics(0, 0);
      CompilerInvocation::CreateFromArgs
        (CI->getInvocation(), argv, argv + argc, CI->getDiagnostics());

      // Reset the diagnostics options that came from CreateFromArgs
      DiagnosticOptions& DiagOpts = CI->getDiagnosticOpts();
      DiagOpts.ShowColors = 1;
      DiagnosticConsumer* Client = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
      CI->createDiagnostics(0, 0, Client);

      // Set the language options, which cling needs
      SetClingCustomLangOpts(CI->getLangOpts());

      if (CI->getHeaderSearchOpts().UseBuiltinIncludes &&
          CI->getHeaderSearchOpts().ResourceDir.empty()) {
        CI->getHeaderSearchOpts().ResourceDir = resource_path.str();
      }
      CI->getInvocation().getPreprocessorOpts().addMacroDef("__CLING__");
      if (CI->getDiagnostics().hasErrorOccurred()) {
        delete CI;
        CI = 0;
        return 0;
      }
    }
    CI->setTarget(TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
                                               CI->getTargetOpts()));
    if (!CI->hasTarget()) {
      delete CI;
      CI = 0;
      return 0;
    }
    CI->getTarget().setForcedLangOptions(CI->getLangOpts());
    SetClingTargetLangOpts(CI->getLangOpts(), CI->getTarget());

    // Set up source and file managers
    CI->createFileManager();
    CI->createSourceManager(CI->getFileManager());

    // Set up the memory buffer
    if (buffer)
      CI->getSourceManager().createMainFileIDForMemBuffer(buffer);

    // Set up the preprocessor
    CI->createPreprocessor();
    Preprocessor& PP = CI->getPreprocessor();
    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
                                           PP.getLangOptions());
    /*NoBuiltins = */ //true);

    // Set up the ASTContext
    ASTContext *Ctx = new ASTContext(CI->getLangOpts(),
                                     PP.getSourceManager(), &CI->getTarget(), PP.getIdentifierTable(),
                                     PP.getSelectorTable(), PP.getBuiltinInfo(), 0);
    CI->setASTContext(Ctx);
    //CI->getSourceManager().clearIDTables(); //do we really need it?

    // Set up the ASTConsumers
    CI->setASTConsumer(new ChainedConsumer());

    // Set up Sema
    CodeCompleteConsumer* CCC = 0;
    CI->createSema(TU_Prefix, CCC);

    // Set CodeGen options
    // CI->getCodeGenOpts().DebugInfo = 1; // want debug info
    // CI->getCodeGenOpts().EmitDeclMetadata = 1; // For unloading, for later
    CI->getCodeGenOpts().OptimizationLevel = 0; // see pure SSA, that comes out
    assert((CI->getCodeGenOpts().VerifyModule == 1)
           && "When asserts are on, let's also assert the module");
    return CI;
  }

  void CIFactory::SetClingCustomLangOpts(LangOptions& Opts) {
    Opts.EmitAllDecls = 1;
    Opts.ObjCNonFragileABI2 = 0;
    Opts.Exceptions = 1;
    Opts.CXXExceptions = 1;
    Opts.Deprecated = 1;
  }

  void CIFactory::SetClingTargetLangOpts(LangOptions& Opts,
                                         const TargetInfo& Target) {
    if (Target.getTriple().getOS() == llvm::Triple::Win32) {
      Opts.MicrosoftExt = 1;
      Opts.MSCVersion = 1300;
      // Should fix http://llvm.org/bugs/show_bug.cgi?id=10528
      Opts.DelayedTemplateParsing = 1;
    } else {
      Opts.MicrosoftExt = 0;
    }
    if (Target.getTriple().getArch() == llvm::Triple::x86) {
       Opts.ObjCNonFragileABI = 1;
    } else {
       Opts.ObjCNonFragileABI = 0;
    }
    if (Target.getTriple().isOSDarwin()) {
       Opts.NeXTRuntime = 1;
    } else {
       Opts.NeXTRuntime = 0;
    }
  }
} // end namespace
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 khelifa Baizid (khelifa.baizid@mines-douai.fr, baizid.khelifa@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
#include <geometry_msgs/PoseStamped.h>
#include <nav_msgs/Odometry.h>

//odometry topic name
std::string mOdometry_topic_name;
//position for the laser in base_link frame
double x_laser, y_laser, z_laser;
//orientation for the laser in base_link frame
double roll_laser, pitch_laser, yaw_laser;
void odometryCallback(const nav_msgs::Odometry::ConstPtr& msg){
  //transform from the base_link to odom frame
  static tf::TransformBroadcaster br;
  tf::Transform transform;
  transform.setOrigin( tf::Vector3(msg->pose.pose.position.x, msg->pose.pose.position.y, 0.0) );
  tf::Quaternion q(0,0,msg->pose.pose.orientation.z,msg->pose.pose.orientation.w);

  transform.setRotation(q);
  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/odom", "/base_link"));
/*
  //transform from the laser to base_link frame
  static tf::TransformBroadcaster br2;
  tf::Transform transform2;
  transform2.setOrigin(tf::Vector3(x_laser, y_laser, z_laser) );
  tf::Quaternion q2;
  q2.setRPY(roll_laser, pitch_laser, yaw_laser);
  transform2.setRotation(q2);
  br2.sendTransform(tf::StampedTransform(transform2, ros::Time::now(), "/base_link", "/laser"));
*/
}

int main(int argc, char** argv){
  ros::init(argc, argv, "turtlebot_car");

  ros::NodeHandle nh;
  ros::NodeHandle private_nh("~");

  //we get the name of the odometry topic
  private_nh.getParam("odometry_topic_name", mOdometry_topic_name);

  //we get paramaters that define the pose of the URG
  //position
  x_laser=0.0;  y_laser=0.0;  z_laser=0.0;
  private_nh.getParam("x_laser", x_laser);private_nh.getParam("y_laser", y_laser);private_nh.getParam("z_laser", z_laser);

  //orientation
  roll_laser=0.0;  pitch_laser=0.0;  yaw_laser=0.0;
  private_nh.getParam("roll_laser", roll_laser);private_nh.getParam("pitch_laser", pitch_laser);private_nh.getParam("yaw_laser", yaw_laser);

  //we define the subscriber to odometry
  ros::Subscriber sub = nh.subscribe<nav_msgs::Odometry>(mOdometry_topic_name, 10, &odometryCallback);

  std::cout<<"***************[ STARING turtlebot_car_node]***************** "<<std::endl;

  ros::spin();
  return 0;
};
<commit_msg>Update turtlebot_car_node.cpp<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 khelifa Baizid (khelifa.baizid@mines-douai.fr, baizid.khelifa@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
#include <geometry_msgs/PoseStamped.h>
#include <nav_msgs/Odometry.h>

//odometry topic name
std::string mOdometry_topic_name;
//position for the laser in base_link frame
double x_laser, y_laser, z_laser;
//orientation for the laser in base_link frame
double roll_laser, pitch_laser, yaw_laser;
void odometryCallback(const nav_msgs::Odometry::ConstPtr& msg){
  //transform from the base_link to odom frame
  static tf::TransformBroadcaster br;
  tf::Transform transform;
  transform.setOrigin( tf::Vector3(msg->pose.pose.position.x, msg->pose.pose.position.y, 0.0) );
  tf::Quaternion q(0,0,msg->pose.pose.orientation.z,msg->pose.pose.orientation.w);

  transform.setRotation(q);
  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/odom", "/base_link"));
/*
  //transform from the laser to base_link frame
  static tf::TransformBroadcaster br2;
  tf::Transform transform2;
  transform2.setOrigin(tf::Vector3(x_laser, y_laser, z_laser) );
  tf::Quaternion q2;
  q2.setRPY(roll_laser, pitch_laser, yaw_laser);
  transform2.setRotation(q2);
  br2.sendTransform(tf::StampedTransform(transform2, ros::Time::now(), "/base_link", "/laser"));
*/
}

int main(int argc, char** argv){
  ros::init(argc, argv, "turtlebot_car");

  ros::NodeHandle nh;
  ros::NodeHandle private_nh("~");

  //we get the name of the odometry topic
  private_nh.getParam("odometry_topic_name", mOdometry_topic_name);
  mOdometry_topic_name = "/odom";
  //we get paramaters that define the pose of the URG
  //position
  x_laser=0.0;  y_laser=0.0;  z_laser=0.0;
  private_nh.getParam("x_laser", x_laser);private_nh.getParam("y_laser", y_laser);private_nh.getParam("z_laser", z_laser);

  //orientation
  roll_laser=0.0;  pitch_laser=0.0;  yaw_laser=0.0;
  private_nh.getParam("roll_laser", roll_laser);private_nh.getParam("pitch_laser", pitch_laser);private_nh.getParam("yaw_laser", yaw_laser);

  //we define the subscriber to odometry
  ros::Subscriber sub = nh.subscribe<nav_msgs::Odometry>(mOdometry_topic_name, 10, &odometryCallback);

  std::cout<<"***************[ STARING turtlebot_car_node]***************** "<<std::endl;

  ros::spin();
  return 0;
};
<|endoftext|>


<commit_before>#pragma once

#include <atomic>
#include <functional>
#include <memory>

#include "lw/error.hpp"

namespace lw {
namespace event {

LW_DEFINE_EXCEPTION(PromiseError);

// ---------------------------------------------------------------------------------------------- //

template<typename T>
class Future;

// ---------------------------------------------------------------------------------------------- //

/// @brief Determines if the given variable is a `Future`, or derives publicly from `Future`.
///
/// @tparam T The type to check.
template<typename T>
struct IsFuture : public std::integral_constant<bool, false>{};

template<typename T>
struct IsFuture<Future<T>> : public std::integral_constant<bool, true>{};

template<template<typename> class T, typename Value>
struct IsFuture<T<Value>> :
    public std::integral_constant<bool, std::is_base_of<Future<Value>, T<Value>>::value>
{};

// ---------------------------------------------------------------------------------------------- //

/// @brief `Promise`s and `Future`s allow for chaining callbacks without nesting.
///
/// A `Promise` is the active side of the pair. Asynchronous functions create a promise and later
/// fulfill it by either resolving or rejecting the promise.
template<typename T = void>
class Promise {
public:
    /// @brief Default construction.
    Promise(void):
        m_state(new _SharedState())
    {
        m_state->resolved   = false;
        m_state->rejected   = false;
        m_state->resolve    = nullptr;
        m_state->reject     = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief No copying!
    Promise(const Promise&) = delete;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Moves the promise from `other` to `this`.
    Promise(Promise&& other):
        m_state(std::move(other.m_state))
    {
        other.m_state = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Returns a future associated with this promise.
    Future<T> future(void);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Resolves the promise as a success.
    void resolve(T&& value){
        m_state->resolved = true;
        if (m_state->resolve) {
            m_state->resolve( std::move( value ) );
        }
    }

    // ------------------------------------------------------------------------------------------ //

    /// @copydoc Promise::resolve(T&&)
    void resolve(const T& value){
        resolve(T(value));
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Rejects the promise as a failure.
    void reject(const error::Exception& err){
        m_state->rejected = true;
        if (m_state->reject) {
            m_state->reject(err);
        }
        else {
            throw err;
        }
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Resets the promise's internal state so that it can be reused.
    ///
    /// @throws PromiseError If the promise is in an unfinished state.
    void reset(void){
        if (!is_finished()) {
            throw PromiseError(1, "Cannot reset an unfinished promise.");
        }
        m_state->resolved   = false;
        m_state->rejected   = false;
        m_state->resolve    = nullptr;
        m_state->reject     = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been resolved.
    bool is_resolved(void) const {
        return m_state->resolved;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been rejected.
    bool is_rejected(void) const {
        return m_state->rejected;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been either resolved or rejected.
    bool is_finished(void) const {
        return is_resolved() || is_rejected();
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief No copying!
    Promise& operator=(const Promise&) = delete;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Moves the promise from `other` into `this`.
    Promise& operator=(Promise&& other){
        m_state = std::move(other.m_state);
        other.m_state = nullptr;
        return *this;
    }

private:
    template<typename Type>
    friend class ::lw::event::Future;

    // ------------------------------------------------------------------------------------------ //

    /// @brief The container for the shared state between promises and futures.
    struct _SharedState {
        std::atomic_bool resolved;
        std::atomic_bool rejected;
        std::function<void(T&&)> resolve;
        std::function<void(const error::Exception&)> reject;
    };
    typedef std::shared_ptr<_SharedState> _SharedStatePtr;

    // ------------------------------------------------------------------------------------------ //

    /// @brief The state of the promise.
    _SharedStatePtr m_state;
};

// ---------------------------------------------------------------------------------------------- //

/// @brief The passive half of the `Promise`-`Future` pair.
///
/// `Future`s are the requester's handle on an asynchronous event. They allow callbacks to be
/// registered for after it has been started.
template<typename T = void>
class Future {
public:
    /// @brief The type promised by this future.
    typedef T result_type;

    /// @brief The type of Promise that made this future.
    typedef Promise<T> promise_type;

    // ------------------------------------------------------------------------------------------ //

    template<typename Func>
    auto then(Func&& func){
        return then(std::forward<Func>(func), nullptr);
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Result, typename Func>
    auto then(Func&& func){
        return then<Result>(std::forward<Func>(func), nullptr);
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Resolve, typename Reject>
    auto then(Resolve&& resolve, Reject&& reject){
        return _then(std::forward<Resolve>(resolve), std::forward<Reject>(reject));
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Result, typename Resolve, typename Reject>
    auto then(Resolve&& resolve, Reject&& reject){
        return _then<Result>(std::forward<Resolve>(resolve), std::forward<Reject>(reject));
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Connects this promise to the one provided.
    ///
    /// @param promise The promise to resolve/reject with this one.
    void then(promise_type&& promise);

    // ------------------------------------------------------------------------------------------ //

private:
    template<typename Type>
    friend class ::lw::event::Promise;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Only `Promise`s can construct us.
    ///
    /// @param state The shared state to associate with.
    Future(const typename promise_type::_SharedStatePtr& state):
        m_state(state)
    {}

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for generic functors.
    ///
    /// @tparam Result  The type given functor promises.
    /// @tparam Resolve A functor type that can take a `Promise&&` as its parameter.
    ///
    /// @param resolve The functor to call when this one is resolved.
    ///
    /// @return A new future, for when the provided `resolve` completes its action.
    template<
        typename Result,
        typename Resolve,
        typename Reject,
        typename = typename std::result_of<Resolve(T&&,Promise<Result>&&)>::type
    >
    Future<Result> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for generic functors promising nothing.
    ///
    /// @tparam Resolve A functor type that can take a `Promise&&` as its parameter.
    ///
    /// @param resolve The functor to call when this one is resolved.
    ///
    /// @return A new future, for when the provided `resolve` completes its action.
    template<
        typename Resolve,
        typename Reject,
        typename = typename std::result_of<Resolve(T&&, Promise<>&&)>::type
    >
    Future<> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for `Future`-returning functors.
    ///
    /// @tparam Resolve A functor which returns a `Future`.
    ///
    /// @param resolve The functor to call when this one is ready.
    ///
    /// @return A `Future` which will be resolved by `resolve`.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<IsFuture<ResolveResult>::value>::type* = nullptr
    >
    Future<typename ResolveResult::result_type> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for value-returning functors (i.e. synchronous ones).
    ///
    /// @tparam Resolve A synchronous functor type.
    ///
    /// @param resolve A synchronous functor returning some value.
    ///
    /// @return A `Future` which will be resolved with the return value from `resolve`.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<
            !IsFuture<ResolveResult>::value &&
            !std::is_void<ResolveResult>::value
        >::type* = nullptr
    >
    Future<ResolveResult> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for void-returning synchronous functors.
    ///
    /// @tparam Resolve A synchronous functor type.
    ///
    /// @param resolve A synchronous functor with no return value.
    ///
    /// @return A `Future` which will be resolved `resolve` runs.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<std::is_void<ResolveResult>::value>::type* = nullptr
    >
    Future<> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Our internal shared state.
    typename promise_type::_SharedStatePtr m_state;
};

}
}
<commit_msg>Added some helper templates<commit_after>#pragma once

#include <atomic>
#include <functional>
#include <memory>
#include <type_traits>

#include "lw/error.hpp"

namespace lw {
namespace event {

LW_DEFINE_EXCEPTION(PromiseError);

// ---------------------------------------------------------------------------------------------- //

template<typename T>
class Future;

// ---------------------------------------------------------------------------------------------- //

/// @brief Determines if the given variable is a `Future`, or derives publicly from `Future`.
///
/// @tparam T The type to check.
template<typename T>
struct IsFuture : public std::integral_constant<bool, false> {};

template<typename T>
struct IsFuture<Future<T>> : public std::integral_constant<bool, true> {};

template<template<typename> class T, typename Value>
struct IsFuture<T<Value>> :
    public std::integral_constant<bool, std::is_base_of<Future<Value>, T<Value>>::value>
{};

// ---------------------------------------------------------------------------------------------- //

/// @brief Breaks down a type to the highest non-future layer.
///
/// @tparam T The type to break down.
template<typename T>
struct UnwrapFuture {
    typedef T result_type;  ///< The type that will be promised.
    typedef Future<T> type; ///< The type of a future for this type.
};

template<typename T>
struct UnwrapFuture<Future<T>> : public UnwrapFuture<T> {};

// ---------------------------------------------------------------------------------------------- //

/// @brief Determines the result of a function as a future.
template<typename T>
struct FutureResultOf;

template<typename F, typename... Args>
struct FutureResultOf<F(Args...)> :
    public UnwrapFuture<typename std::result_of<F(Args...)>::type>
{};

// ---------------------------------------------------------------------------------------------- //

/// @brief `Promise`s and `Future`s allow for chaining callbacks without nesting.
///
/// A `Promise` is the active side of the pair. Asynchronous functions create a promise and later
/// fulfill it by either resolving or rejecting the promise.
template<typename T = void>
class Promise {
public:
    /// @brief Default construction.
    Promise(void):
        m_state(new _SharedState())
    {
        m_state->resolved   = false;
        m_state->rejected   = false;
        m_state->resolve    = nullptr;
        m_state->reject     = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief No copying!
    Promise(const Promise&) = delete;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Moves the promise from `other` to `this`.
    Promise(Promise&& other):
        m_state(std::move(other.m_state))
    {
        other.m_state = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Returns a future associated with this promise.
    Future<T> future(void);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Resolves the promise as a success.
    void resolve(T&& value){
        m_state->resolved = true;
        if (m_state->resolve) {
            m_state->resolve( std::move( value ) );
        }
    }

    // ------------------------------------------------------------------------------------------ //

    /// @copydoc Promise::resolve(T&&)
    void resolve(const T& value){
        resolve(T(value));
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Rejects the promise as a failure.
    void reject(const error::Exception& err){
        m_state->rejected = true;
        if (m_state->reject) {
            m_state->reject(err);
        }
        else {
            throw err;
        }
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Resets the promise's internal state so that it can be reused.
    ///
    /// @throws PromiseError If the promise is in an unfinished state.
    void reset(void){
        if (!is_finished()) {
            throw PromiseError(1, "Cannot reset an unfinished promise.");
        }
        m_state->resolved   = false;
        m_state->rejected   = false;
        m_state->resolve    = nullptr;
        m_state->reject     = nullptr;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been resolved.
    bool is_resolved(void) const {
        return m_state->resolved;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been rejected.
    bool is_rejected(void) const {
        return m_state->rejected;
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Indicates if the promise has been either resolved or rejected.
    bool is_finished(void) const {
        return is_resolved() || is_rejected();
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief No copying!
    Promise& operator=(const Promise&) = delete;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Moves the promise from `other` into `this`.
    Promise& operator=(Promise&& other){
        m_state = std::move(other.m_state);
        other.m_state = nullptr;
        return *this;
    }

private:
    template<typename Type>
    friend class ::lw::event::Future;

    // ------------------------------------------------------------------------------------------ //

    /// @brief The container for the shared state between promises and futures.
    struct _SharedState {
        std::atomic_bool resolved;
        std::atomic_bool rejected;
        std::function<void(T&&)> resolve;
        std::function<void(const error::Exception&)> reject;
    };
    typedef std::shared_ptr<_SharedState> _SharedStatePtr;

    // ------------------------------------------------------------------------------------------ //

    /// @brief The state of the promise.
    _SharedStatePtr m_state;
};

// ---------------------------------------------------------------------------------------------- //

/// @brief The passive half of the `Promise`-`Future` pair.
///
/// `Future`s are the requester's handle on an asynchronous event. They allow callbacks to be
/// registered for after it has been started.
template<typename T = void>
class Future {
public:
    /// @brief The type promised by this future.
    typedef T result_type;

    /// @brief The type of Promise that made this future.
    typedef Promise<T> promise_type;

    // ------------------------------------------------------------------------------------------ //

    template<typename Func>
    auto then(Func&& func){
        return then(std::forward<Func>(func), nullptr);
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Result, typename Func>
    auto then(Func&& func){
        return then<Result>(std::forward<Func>(func), nullptr);
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Resolve, typename Reject>
    auto then(Resolve&& resolve, Reject&& reject){
        return _then(std::forward<Resolve>(resolve), std::forward<Reject>(reject));
    }

    // ------------------------------------------------------------------------------------------ //

    template<typename Result, typename Resolve, typename Reject>
    auto then(Resolve&& resolve, Reject&& reject){
        return _then<Result>(std::forward<Resolve>(resolve), std::forward<Reject>(reject));
    }

    // ------------------------------------------------------------------------------------------ //

    /// @brief Connects this promise to the one provided.
    ///
    /// @param promise The promise to resolve/reject with this one.
    void then(promise_type&& promise);

    // ------------------------------------------------------------------------------------------ //

private:
    template<typename Type>
    friend class ::lw::event::Promise;

    // ------------------------------------------------------------------------------------------ //

    /// @brief Only `Promise`s can construct us.
    ///
    /// @param state The shared state to associate with.
    Future(const typename promise_type::_SharedStatePtr& state):
        m_state(state)
    {}

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for generic functors.
    ///
    /// @tparam Result  The type given functor promises.
    /// @tparam Resolve A functor type that can take a `Promise&&` as its parameter.
    ///
    /// @param resolve The functor to call when this one is resolved.
    ///
    /// @return A new future, for when the provided `resolve` completes its action.
    template<
        typename Result,
        typename Resolve,
        typename Reject,
        typename = typename std::result_of<Resolve(T&&,Promise<Result>&&)>::type
    >
    Future<Result> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for generic functors promising nothing.
    ///
    /// @tparam Resolve A functor type that can take a `Promise&&` as its parameter.
    ///
    /// @param resolve The functor to call when this one is resolved.
    ///
    /// @return A new future, for when the provided `resolve` completes its action.
    template<
        typename Resolve,
        typename Reject,
        typename = typename std::result_of<Resolve(T&&, Promise<>&&)>::type
    >
    Future<> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for `Future`-returning functors.
    ///
    /// @tparam Resolve A functor which returns a `Future`.
    ///
    /// @param resolve The functor to call when this one is ready.
    ///
    /// @return A `Future` which will be resolved by `resolve`.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<IsFuture<ResolveResult>::value>::type* = nullptr
    >
    Future<typename ResolveResult::result_type> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for value-returning functors (i.e. synchronous ones).
    ///
    /// @tparam Resolve A synchronous functor type.
    ///
    /// @param resolve A synchronous functor returning some value.
    ///
    /// @return A `Future` which will be resolved with the return value from `resolve`.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<
            !IsFuture<ResolveResult>::value &&
            !std::is_void<ResolveResult>::value
        >::type* = nullptr
    >
    Future<ResolveResult> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Chaining for void-returning synchronous functors.
    ///
    /// @tparam Resolve A synchronous functor type.
    ///
    /// @param resolve A synchronous functor with no return value.
    ///
    /// @return A `Future` which will be resolved `resolve` runs.
    template<
        typename Resolve,
        typename Reject,
        typename ResolveResult = typename std::result_of<Resolve(T&&)>::type,
        typename std::enable_if<std::is_void<ResolveResult>::value>::type* = nullptr
    >
    Future<> _then(Resolve&& resolve, Reject&& reject);

    // ------------------------------------------------------------------------------------------ //

    /// @brief Our internal shared state.
    typename promise_type::_SharedStatePtr m_state;
};

}
}
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of Guichan 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab)
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab()
    {
        return mSelectedTab;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw(Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(Rectangle(1, 1,
                                              getWidth() - 2,
                                              getHeight() - 2));
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor(getBaseColor());
            graphics->drawLine(mSelectedTab->getX() + 1,
                               mTabContainer->getHeight(),
                               mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                               mTabContainer->getHeight());

        }

        drawChildren(graphics);
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();
        }
    }

    void TabbedArea::setWidth(int width)
    {
        Widget::setWidth(width);
        adjustSize();
    }

    void TabbedArea::setHeight(int height)
    {
        gcn::Rectangle dim = mDimension;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setHeight(height);
    }

    void TabbedArea::setSize(int width, int height)
    {
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setSize(width, height);
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        gcn::Rectangle dim = mDimension;
        mDimension.x = dimension.x;
        mDimension.y = dimension.y;
        mDimension.width = dimension.width;
        mDimension.height = dimension.height;
        adjustSize();
        Widget::setDimension(dimension);
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::Left)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::Right)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::Left)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab(tab);
            }
        }

        // Request focus only if the source of the event
        // is not focusble. If the source of the event
        // is focused we don't want to steal the focus.
        if (!mouseEvent.getSource()->isFocusable())
        {
            requestFocus();
        }
    }

    void TabbedArea::death(const Event& event)
    {
        Widget* source = event.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }

    void TabbedArea::setBaseColor(const Color& color)
    {
        Widget::setBaseColor(color);
        mWidgetContainer->setBaseColor(color);
        mTabContainer->setBaseColor(color);
    }
}
<commit_msg>Comments about resizing have been added. setWidth now properly adjusts the size before calling Widget::setWidth.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of Guichan 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab)
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab()
    {
        return mSelectedTab;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw(Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(Rectangle(1, 1,
                                              getWidth() - 2,
                                              getHeight() - 2));
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor(getBaseColor());
            graphics->drawLine(mSelectedTab->getX() + 1,
                               mTabContainer->getHeight(),
                               mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                               mTabContainer->getHeight());

        }

        drawChildren(graphics);
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();
        }
    }

    void TabbedArea::setWidth(int width)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setWidth as
        // Widget::setWidth might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        adjustSize();
        mDimension = dim;
        Widget::setWidth(width);
    }

    void TabbedArea::setHeight(int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setHeight as
        // Widget::setHeight might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setHeight(height);
    }

    void TabbedArea::setSize(int width, int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setSize as
        // Widget::setSize might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setSize(width, height);
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setDimension as
        // Widget::setDimension might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension = dimension;
        adjustSize();
        Widget::setDimension(dimension);
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::Left)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::Right)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::Left)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab(tab);
            }
        }

        // Request focus only if the source of the event
        // is not focusble. If the source of the event
        // is focused we don't want to steal the focus.
        if (!mouseEvent.getSource()->isFocusable())
        {
            requestFocus();
        }
    }

    void TabbedArea::death(const Event& event)
    {
        Widget* source = event.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }

    void TabbedArea::setBaseColor(const Color& color)
    {
        Widget::setBaseColor(color);
        mWidgetContainer->setBaseColor(color);
        mTabContainer->setBaseColor(color);
    }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#include <dlfcn.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mutex>
#include <JavaScriptCore/JSContextRef.h>

#include "js_init.h"
#include "shared_realm.hpp"
#include "realm_coordinator.hpp"

#if __arm__
#define HOOK_SIZE 8
#else
#define HOOK_SIZE 5
#endif

bool realmContextInjected;

static void swap_function() __attribute__((constructor));

static JSGlobalContextRef create_context(JSContextGroupRef group, JSClassRef global_class)
{
    static std::mutex s_mutex;
    std::lock_guard<std::mutex> lock(s_mutex);

    // Replace JSGlobalContextCreateInGroup with its original implementation and call it.
    swap_function();
    JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(group, global_class);

    // Reinstall the hook.
    swap_function();

    // Clear cache from previous instances.
    realm::_impl::RealmCoordinator::clear_all_caches();

    RJSInitializeInContext(ctx);
    realmContextInjected = true;
    return ctx;
}

static void swap_function()
{
    static int8_t s_orig_code[HOOK_SIZE];
    static bool s_swapped = false;

    int8_t *orig_func = (int8_t*)&JSGlobalContextCreateInGroup;
    int8_t *new_func = (int8_t*)&create_context;

#if __arm__
    bool orig_thumb = (uintptr_t)orig_func % 4 != 0;
    if (orig_thumb) {
        orig_func--;
    }
#endif

    size_t page_size = sysconf(_SC_PAGESIZE);
    uintptr_t page_start = (uintptr_t)orig_func & ~(page_size - 1);
    uintptr_t code_end = (uintptr_t)orig_func + HOOK_SIZE;

    // Make this memory region writable.
    mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_WRITE | PROT_EXEC);

    if (s_swapped) {
        // Copy original code back into place.
        memcpy(orig_func, s_orig_code, HOOK_SIZE);
    } else {
        // Store the original code before replacing it.
        memcpy(s_orig_code, orig_func, HOOK_SIZE);

#if __arm__
        if (orig_thumb) {
            // LDR PC, [PC, #0]; BX PC;
            memcpy(orig_func, "\x00\x4f\x38\x47", 4);
            memcpy(orig_func + 4, &new_func, 4);
        } else {
            // LDR PC, [PC, #0];
            memcpy(orig_func, "\x00\xf0\x9f\xe5", 4);
            memcpy(orig_func + 4, &new_func, 4);
        }
#else
        int32_t jmp_offset = (int64_t)new_func - (int64_t)orig_func - HOOK_SIZE;

        // Change original function to jump to our new one.
        *orig_func = 0xE9; // JMP
        *(int32_t*)(orig_func + 1) = jmp_offset;
#endif
    }

    s_swapped = !s_swapped;

    // Return this region to no longer being writable.
    mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_EXEC);
}
<commit_msg>Fix ARM hook into JSGlobalContextCreateInGroup<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#include <dlfcn.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mutex>
#include <JavaScriptCore/JSContextRef.h>

#include "js_init.h"
#include "shared_realm.hpp"
#include "realm_coordinator.hpp"

#if __arm__
#define HOOK_SIZE 8
#else
#define HOOK_SIZE 5
#endif

bool realmContextInjected;

static void swap_function() __attribute__((constructor));

static JSGlobalContextRef create_context(JSContextGroupRef group, JSClassRef global_class)
{
    static std::mutex s_mutex;
    std::lock_guard<std::mutex> lock(s_mutex);

    // Replace JSGlobalContextCreateInGroup with its original implementation and call it.
    swap_function();
    JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(group, global_class);

    // Reinstall the hook.
    swap_function();

    // Clear cache from previous instances.
    realm::_impl::RealmCoordinator::clear_all_caches();

    RJSInitializeInContext(ctx);
    realmContextInjected = true;
    return ctx;
}

static void swap_function()
{
    static int8_t s_orig_code[HOOK_SIZE];
    static bool s_swapped = false;

    int8_t *orig_func = (int8_t*)&JSGlobalContextCreateInGroup;
    int8_t *new_func = (int8_t*)&create_context;

#if __arm__
    bool orig_thumb = (uintptr_t)orig_func % 4 != 0;
    if (orig_thumb) {
        orig_func--;
    }
#endif

    size_t page_size = sysconf(_SC_PAGESIZE);
    uintptr_t page_start = (uintptr_t)orig_func & ~(page_size - 1);
    uintptr_t code_end = (uintptr_t)orig_func + HOOK_SIZE;

    // Make this memory region writable.
    mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_WRITE | PROT_EXEC);

    if (s_swapped) {
        // Copy original code back into place.
        memcpy(orig_func, s_orig_code, HOOK_SIZE);
    } else {
        // Store the original code before replacing it.
        memcpy(s_orig_code, orig_func, HOOK_SIZE);

#if __arm__
        if (orig_thumb) {
            // LDR R3, [PC, #0]; BX R3;
            memcpy(orig_func, "\x00\x4b\x18\x47", 4);
            memcpy(orig_func + 4, &new_func, 4);
        } else {
            // LDR PC, [PC, #0];
            memcpy(orig_func, "\x00\xf0\x9f\xe5", 4);
            memcpy(orig_func + 4, &new_func, 4);
        }
#else
        int32_t jmp_offset = (int64_t)new_func - (int64_t)orig_func - HOOK_SIZE;

        // Change original function to jump to our new one.
        *orig_func = 0xE9; // JMP
        *(int32_t*)(orig_func + 1) = jmp_offset;
#endif
    }

    s_swapped = !s_swapped;

#if __arm__
    // Clear ARM instruction cache.
    {
        register unsigned long begin __asm("a1") = (unsigned long)orig_func;
        register unsigned long end __asm("a2") = (unsigned long)code_end;
        register unsigned long flag __asm("a3") = 0;
        register unsigned long scno __asm("r7") = 0xf0002;
        __asm __volatile (
            "swi 0 @ sys_cacheflush"
            : "=r" (begin)
            : "0" (begin), "r" (end), "r" (flag), "r" (scno)
        );
    };
#endif
    // Return this region to no longer being writable.
    mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_EXEC);
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.18  2001/03/20 08:21:55  coppedis
ZDC needs PIPE, ABSO, DIPO and SHIL

Revision 1.17  2001/03/16 16:18:03  coppedis
Correction for superposition of ZDC volumes with MUON arm one

Revision 1.16  2001/03/15 16:01:11  coppedis
Code review

Revision 1.15  2001/01/26 19:56:27  hristov
Major upgrade of AliRoot code

Revision 1.14  2000/12/12 13:17:01  coppedis
Minor corrections suggested by P. Hristov

Revision 1.12  2000/12/01 08:19:01  coppedis
Adding a message error if ZDC is constructed without DIPO

Revision 1.11  2000/11/30 17:21:03  coppedis
Introduce hit array fStHits reset only at the end of the event (for digitization)

Revision 1.10  2000/11/22 11:32:58  coppedis
Major code revision

Revision 1.9  2000/10/02 21:28:20  fca
Removal of useless dependecies via forward declarations

Revision 1.8  2000/07/10 13:58:01  fca
New version of ZDC from E.Scomparin & C.Oppedisano

Revision 1.7  2000/01/19 17:17:40  fca

Revision 1.6  1999/09/29 09:24:35  fca
Introduction of the Copyright and cvs Log

*/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Zero Degree Calorimeter                                                  //
//  This class contains the basic functions for the ZDCs                     //
//  Functions specific to one particular geometry are      	             //
//  contained in the derived classes                                         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

// --- ROOT system
#include <TBRIK.h>
#include <TNode.h>
#include <TGeometry.h>
#include <TFile.h>
#include <TTree.h>

// --- AliRoot header files
#include "AliZDC.h"
#include "AliZDCHit.h"
#include "AliRun.h"
#include "AliDetector.h"
#include "AliCallf77.h"
#include "AliConst.h"
#include "AliMC.h"

ClassImp(AliZDC)

//_____________________________________________________________________________
AliZDC::AliZDC()
{
  //
  // Default constructor for the Zero Degree Calorimeter base class
  //

  fIshunt = 1;

  fNhits = 0;

  fNStHits = 0;

  fNPrimaryHits = 0;
  fNoShower   = 0;
}

//_____________________________________________________________________________
AliZDC::AliZDC(const char *name, const char *title)
  : AliDetector(name,title)
{
  //
  // Standard constructor for the Zero Degree Calorimeter base class
  //

  // Check that DIPO is there (otherwise tracking is wrong!!!)

  AliModule* PIPE=gAlice->GetModule("PIPE");
  AliModule* ABSO=gAlice->GetModule("ABSO");
  AliModule* DIPO=gAlice->GetModule("DIPO");
  AliModule* SHIL=gAlice->GetModule("SHIL");
  if((!PIPE) || (!ABSO) || (!DIPO) || (!SHIL)) {
    Error("Constructor","ZDC needs PIPE, ABSO, DIPO and SHIL!!!\n");
    exit(1);
  }

  //
  // Allocate the array of hits

  fIshunt =  1;

  fHits   = new TClonesArray("AliZDCHit",1000);
  gAlice->AddHitList(fHits);

  fStHits = new TClonesArray("AliZDCHit",1000);
  fNStHits = 0;

  fNPrimaryHits = 0;
  fNoShower   = 0;

}
//____________________________________________________________________________
AliZDC::~AliZDC()
{
  //
  // ZDC destructor
  //

  fIshunt   = 0;

//  delete fHits;
//  if(fStHits){
//    fStHits->Delete();
//    delete fStHits;
//    fNStHits = 0;
//  }
//  delete fDigits;
}
//_____________________________________________________________________________
void AliZDC::AddHit(Int_t track, Int_t *vol, Float_t *hits)
{
  //
  // 		Add a ZDC hit to the hit list.
  // -> We make use of 2 array of hits:
  // [1]  fHits (the usual one) that contains hits for each PRIMARY
  // [2]  fStHits that contains hits for each EVENT and is used to
  //	  obtain digits at the end of each event
  //

  static Float_t primKinEn, xImpact, yImpact, sFlag;

  AliZDCHit *newquad, *curevquad, *curprimquad;
  newquad = new AliZDCHit(fIshunt, track, vol, hits);

  TClonesArray &lsthits = *fStHits;
  TClonesArray &lhits = *fHits;

  Int_t i,j,kStHit = 1;
  for(i=0; i<fNStHits; i++){
    // If hits are equal (same track, same volume), sum them.
     curevquad = (AliZDCHit*) lsthits[i];
     kStHit = 1;
     if(*curevquad == *newquad){
        *curevquad = *curevquad+*newquad;
        kStHit = 0;
     }
  }

  for(j=0; j<fNhits; j++){
    // If hits are equal (same track, same volume), sum them.
     curprimquad = (AliZDCHit*) lhits[j];
     if(*curprimquad == *newquad){
        *curprimquad = *curprimquad+*newquad;
	delete newquad;
	return;
     }
  }

  if(fNhits==0){
      // First hit -> setting flag for primary or secondary particle
      Int_t primary = gAlice->GetPrimary(track);
      if(track != primary){
        newquad->fSFlag = 1;  // Hit created by secondary particle entering the ZDC
      }
      else if(track == primary){
        newquad->fSFlag = 0;  // Hit created by PRIMARY particle entering the ZDC
      }
      fNPrimaryHits += 1;
      sFlag = newquad->fSFlag;
      primKinEn = newquad->fPrimKinEn;
      xImpact = newquad->fXImpact;
      yImpact = newquad->fYImpact;
   }
   else{
      newquad->fPrimKinEn = primKinEn;
      newquad->fXImpact = xImpact;
      newquad->fYImpact = yImpact;
      newquad->fSFlag = sFlag;
   }

    //Otherwise create a new hit
    new(lhits[fNhits]) AliZDCHit(newquad);
    fNhits++;

    if(kStHit){
      new(lsthits[fNStHits]) AliZDCHit(newquad);
      fNStHits++;
    }

//    if(fDebug == 1){
      printf("\n  Primary Hits --------------------------------------------------------\n");
      fHits->Print("");
      printf("\n  Event Hits --------------------------------------------------------\n");
      fStHits->Print("");
//    }

    delete newquad;
  }

//_____________________________________________________________________________
void AliZDC::ResetDigits()
{
  //
  // Reset number of digits and the digits array
  //

    AliDetector::ResetDigits();
//    fNStHits = 0;
//    if(fStHits) fStHits->Clear();
}

//_____________________________________________________________________________
void AliZDC::BuildGeometry()
{
  //
  // Build the ROOT TNode geometry for event display
  // in the Zero Degree Calorimeter
  // This routine is dummy for the moment
  //

  TNode *node, *top;
  TBRIK *brik;
  const int kColorZDC  = kRed;

  //
  top=gAlice->GetGeometry()->GetNode("alice");

  // ZDC
    brik = new TBRIK("S_ZDC","ZDC box","void",300,300,5);
    top->cd();
    node = new TNode("ZDC","ZDC","S_ZDC",0,0,600,"");
    node->SetLineColor(kColorZDC);
    fNodes->Add(node);
}

//_____________________________________________________________________________
Int_t AliZDC::DistancetoPrimitive(Int_t , Int_t )
{
  //
  // Distance from the mouse to the Zero Degree Calorimeter
  // Dummy routine
  //
  return 9999;
}

//_____________________________________________________________________________
void AliZDC::StepManager()
{
  //
  // Routine called at every step in the Zero Degree Calorimeter
  //
}
<commit_msg>Comment prints<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.19  2001/03/26 09:10:23  coppedis
Corrected bug in constructor (fIshunt has to be =1)

Revision 1.18  2001/03/20 08:21:55  coppedis
ZDC needs PIPE, ABSO, DIPO and SHIL

Revision 1.17  2001/03/16 16:18:03  coppedis
Correction for superposition of ZDC volumes with MUON arm one

Revision 1.16  2001/03/15 16:01:11  coppedis
Code review

Revision 1.15  2001/01/26 19:56:27  hristov
Major upgrade of AliRoot code

Revision 1.14  2000/12/12 13:17:01  coppedis
Minor corrections suggested by P. Hristov

Revision 1.12  2000/12/01 08:19:01  coppedis
Adding a message error if ZDC is constructed without DIPO

Revision 1.11  2000/11/30 17:21:03  coppedis
Introduce hit array fStHits reset only at the end of the event (for digitization)

Revision 1.10  2000/11/22 11:32:58  coppedis
Major code revision

Revision 1.9  2000/10/02 21:28:20  fca
Removal of useless dependecies via forward declarations

Revision 1.8  2000/07/10 13:58:01  fca
New version of ZDC from E.Scomparin & C.Oppedisano

Revision 1.7  2000/01/19 17:17:40  fca

Revision 1.6  1999/09/29 09:24:35  fca
Introduction of the Copyright and cvs Log

*/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Zero Degree Calorimeter                                                  //
//  This class contains the basic functions for the ZDCs                     //
//  Functions specific to one particular geometry are      	             //
//  contained in the derived classes                                         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

// --- ROOT system
#include <TBRIK.h>
#include <TNode.h>
#include <TGeometry.h>
#include <TFile.h>
#include <TTree.h>

// --- AliRoot header files
#include "AliZDC.h"
#include "AliZDCHit.h"
#include "AliRun.h"
#include "AliDetector.h"
#include "AliCallf77.h"
#include "AliConst.h"
#include "AliMC.h"

ClassImp(AliZDC)

//_____________________________________________________________________________
AliZDC::AliZDC()
{
  //
  // Default constructor for the Zero Degree Calorimeter base class
  //

  fIshunt = 1;

  fNhits = 0;

  fNStHits = 0;

  fNPrimaryHits = 0;
  fNoShower   = 0;
}

//_____________________________________________________________________________
AliZDC::AliZDC(const char *name, const char *title)
  : AliDetector(name,title)
{
  //
  // Standard constructor for the Zero Degree Calorimeter base class
  //

  // Check that DIPO is there (otherwise tracking is wrong!!!)

  AliModule* PIPE=gAlice->GetModule("PIPE");
  AliModule* ABSO=gAlice->GetModule("ABSO");
  AliModule* DIPO=gAlice->GetModule("DIPO");
  AliModule* SHIL=gAlice->GetModule("SHIL");
  if((!PIPE) || (!ABSO) || (!DIPO) || (!SHIL)) {
    Error("Constructor","ZDC needs PIPE, ABSO, DIPO and SHIL!!!\n");
    exit(1);
  }

  //
  // Allocate the array of hits

  fIshunt =  1;

  fHits   = new TClonesArray("AliZDCHit",1000);
  gAlice->AddHitList(fHits);

  fStHits = new TClonesArray("AliZDCHit",1000);
  fNStHits = 0;

  fNPrimaryHits = 0;
  fNoShower   = 0;

}
//____________________________________________________________________________
AliZDC::~AliZDC()
{
  //
  // ZDC destructor
  //

  fIshunt   = 0;

//  delete fHits;
//  if(fStHits){
//    fStHits->Delete();
//    delete fStHits;
//    fNStHits = 0;
//  }
//  delete fDigits;
}
//_____________________________________________________________________________
void AliZDC::AddHit(Int_t track, Int_t *vol, Float_t *hits)
{
  //
  // 		Add a ZDC hit to the hit list.
  // -> We make use of 2 array of hits:
  // [1]  fHits (the usual one) that contains hits for each PRIMARY
  // [2]  fStHits that contains hits for each EVENT and is used to
  //	  obtain digits at the end of each event
  //

  static Float_t primKinEn, xImpact, yImpact, sFlag;

  AliZDCHit *newquad, *curevquad, *curprimquad;
  newquad = new AliZDCHit(fIshunt, track, vol, hits);

  TClonesArray &lsthits = *fStHits;
  TClonesArray &lhits = *fHits;

  Int_t i,j,kStHit = 1;
  for(i=0; i<fNStHits; i++){
    // If hits are equal (same track, same volume), sum them.
     curevquad = (AliZDCHit*) lsthits[i];
     kStHit = 1;
     if(*curevquad == *newquad){
        *curevquad = *curevquad+*newquad;
        kStHit = 0;
     }
  }

  for(j=0; j<fNhits; j++){
    // If hits are equal (same track, same volume), sum them.
     curprimquad = (AliZDCHit*) lhits[j];
     if(*curprimquad == *newquad){
        *curprimquad = *curprimquad+*newquad;
	delete newquad;
	return;
     }
  }

  if(fNhits==0){
      // First hit -> setting flag for primary or secondary particle
      Int_t primary = gAlice->GetPrimary(track);
      if(track != primary){
        newquad->fSFlag = 1;  // Hit created by secondary particle entering the ZDC
      }
      else if(track == primary){
        newquad->fSFlag = 0;  // Hit created by PRIMARY particle entering the ZDC
      }
      fNPrimaryHits += 1;
      sFlag = newquad->fSFlag;
      primKinEn = newquad->fPrimKinEn;
      xImpact = newquad->fXImpact;
      yImpact = newquad->fYImpact;
   }
   else{
      newquad->fPrimKinEn = primKinEn;
      newquad->fXImpact = xImpact;
      newquad->fYImpact = yImpact;
      newquad->fSFlag = sFlag;
   }

    //Otherwise create a new hit
    new(lhits[fNhits]) AliZDCHit(newquad);
    fNhits++;

    if(kStHit){
      new(lsthits[fNStHits]) AliZDCHit(newquad);
      fNStHits++;
    }

//    if(fDebug == 1){
//      printf("\n  Primary Hits --------------------------------------------------------\n");
//      fHits->Print("");
//      printf("\n  Event Hits --------------------------------------------------------\n");
//      fStHits->Print("");
//    }

    delete newquad;
  }

//_____________________________________________________________________________
void AliZDC::ResetDigits()
{
  //
  // Reset number of digits and the digits array
  //

    AliDetector::ResetDigits();
//    fNStHits = 0;
//    if(fStHits) fStHits->Clear();
}

//_____________________________________________________________________________
void AliZDC::BuildGeometry()
{
  //
  // Build the ROOT TNode geometry for event display
  // in the Zero Degree Calorimeter
  // This routine is dummy for the moment
  //

  TNode *node, *top;
  TBRIK *brik;
  const int kColorZDC  = kRed;

  //
  top=gAlice->GetGeometry()->GetNode("alice");

  // ZDC
    brik = new TBRIK("S_ZDC","ZDC box","void",300,300,5);
    top->cd();
    node = new TNode("ZDC","ZDC","S_ZDC",0,0,600,"");
    node->SetLineColor(kColorZDC);
    fNodes->Add(node);
}

//_____________________________________________________________________________
Int_t AliZDC::DistancetoPrimitive(Int_t , Int_t )
{
  //
  // Distance from the mouse to the Zero Degree Calorimeter
  // Dummy routine
  //
  return 9999;
}

//_____________________________________________________________________________
void AliZDC::StepManager()
{
  //
  // Routine called at every step in the Zero Degree Calorimeter
  //
}
<|endoftext|>