<commit_before>//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements misc. GraphWriter support routines.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GraphWriter.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
#include "llvm/Config/config.h"
using namespace llvm;

std::string llvm::DOT::EscapeString(const std::string &Label) {
  std::string Str(Label);
  for (unsigned i = 0; i != Str.length(); ++i)
  switch (Str[i]) {
    case '\n':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;
      Str[i] = 'n';
      break;
    case '\t':
      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      ++i;
      Str[i] = ' ';
      break;
    case '\\':
      if (i+1 != Str.length())
        switch (Str[i+1]) {
          case 'l': continue; // don't disturb \l
          case '|': case '{': case '}':
            Str.erase(Str.begin()+i); continue;
          default: break;
        }
    case '{': case '}':
    case '<': case '>':
    case '|': case '"':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;  // don't infinite loop
      break;
  }
  return Str;
}

void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
                        GraphProgram::Name program) {
  std::string ErrMsg;
#if HAVE_GRAPHVIZ
  sys::Path Graphviz(LLVM_PATH_GRAPHVIZ);

  std::vector<const char*> args;
  args.push_back(Graphviz.c_str());
  args.push_back(Filename.c_str());
  args.push_back(0);

  errs() << "Running 'Graphviz' program... ";
  if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg))
    errs() << "Error viewing graph " << Filename.str() << ": " << ErrMsg
           << "\n";
  else
    Filename.eraseFromDisk();

#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \
                   HAVE_TWOPI || HAVE_CIRCO))
  sys::Path PSFilename = Filename;
  PSFilename.appendSuffix("ps");

  sys::Path prog;

  // Set default grapher
#if HAVE_CIRCO
  prog = sys::Path(LLVM_PATH_CIRCO);
#endif
#if HAVE_TWOPI
  prog = sys::Path(LLVM_PATH_TWOPI);
#endif
#if HAVE_NEATO
  prog = sys::Path(LLVM_PATH_NEATO);
#endif
#if HAVE_FDP
  prog = sys::Path(LLVM_PATH_FDP);
#endif
#if HAVE_DOT
  prog = sys::Path(LLVM_PATH_DOT);
#endif

  // Find which program the user wants
#if HAVE_DOT
  if (program == GraphProgram::DOT)
    prog = sys::Path(LLVM_PATH_DOT);
#endif
#if (HAVE_FDP)
  if (program == GraphProgram::FDP)
    prog = sys::Path(LLVM_PATH_FDP);
#endif
#if (HAVE_NEATO)
  if (program == GraphProgram::NEATO)
    prog = sys::Path(LLVM_PATH_NEATO);
#endif
#if (HAVE_TWOPI)
  if (program == GraphProgram::TWOPI)
    prog = sys::Path(LLVM_PATH_TWOPI);
#endif
#if (HAVE_CIRCO)
  if (program == GraphProgram::CIRCO)
    prog = sys::Path(LLVM_PATH_CIRCO);
#endif

  std::vector<const char*> args;
  args.push_back(prog.c_str());
  args.push_back("-Tps");
  args.push_back("-Nfontname=Courier");
  args.push_back("-Gsize=7.5,10");
  args.push_back(Filename.c_str());
  args.push_back("-o");
  args.push_back(PSFilename.c_str());
  args.push_back(0);

  errs() << "Running '" << prog.str() << "' program... ";

  if (sys::Program::ExecuteAndWait(prog, &args[0], 0, 0, 0, 0, &ErrMsg)) {
     errs() << "Error viewing graph " << Filename.str() << ": '"
            << ErrMsg << "\n";
  } else {
    errs() << " done. \n";

    sys::Path gv(LLVM_PATH_GV);
    args.clear();
    args.push_back(gv.c_str());
    args.push_back(PSFilename.c_str());
    args.push_back("--spartan");
    args.push_back(0);

    ErrMsg.clear();
    if (wait) {
       if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg))
          errs() << "Error viewing graph: " << ErrMsg << "\n";
       Filename.eraseFromDisk();
       PSFilename.eraseFromDisk();
    }
    else {
       sys::Program::ExecuteNoWait(gv, &args[0],0,0,0,&ErrMsg);
       errs() << "Remember to erase graph files: " << Filename.str() << " "
              << PSFilename.str() << "\n";
    }
  }
#elif HAVE_DOTTY
  sys::Path dotty(LLVM_PATH_DOTTY);

  std::vector<const char*> args;
  args.push_back(dotty.c_str());
  args.push_back(Filename.c_str());
  args.push_back(0);

  errs() << "Running 'dotty' program... ";
  if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) {
     errs() << "Error viewing graph " << Filename.str() << ": "
            << ErrMsg << "\n";
  } else {
#ifdef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns
    return;
#endif
    Filename.eraseFromDisk();
  }
#endif
}
<commit_msg>Fix PR6826: GraphWriter delete the generated file before "dotty" load it, patch by 'ether'.<commit_after>//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements misc. GraphWriter support routines.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/GraphWriter.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
#include "llvm/Config/config.h"
using namespace llvm;

std::string llvm::DOT::EscapeString(const std::string &Label) {
  std::string Str(Label);
  for (unsigned i = 0; i != Str.length(); ++i)
  switch (Str[i]) {
    case '\n':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;
      Str[i] = 'n';
      break;
    case '\t':
      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      ++i;
      Str[i] = ' ';
      break;
    case '\\':
      if (i+1 != Str.length())
        switch (Str[i+1]) {
          case 'l': continue; // don't disturb \l
          case '|': case '{': case '}':
            Str.erase(Str.begin()+i); continue;
          default: break;
        }
    case '{': case '}':
    case '<': case '>':
    case '|': case '"':
      Str.insert(Str.begin()+i, '\\');  // Escape character...
      ++i;  // don't infinite loop
      break;
  }
  return Str;
}

void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
                        GraphProgram::Name program) {
  std::string ErrMsg;
#if HAVE_GRAPHVIZ
  sys::Path Graphviz(LLVM_PATH_GRAPHVIZ);

  std::vector<const char*> args;
  args.push_back(Graphviz.c_str());
  args.push_back(Filename.c_str());
  args.push_back(0);

  errs() << "Running 'Graphviz' program... ";
  if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg))
    errs() << "Error viewing graph " << Filename.str() << ": " << ErrMsg
           << "\n";
  else
    Filename.eraseFromDisk();

#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \
                   HAVE_TWOPI || HAVE_CIRCO))
  sys::Path PSFilename = Filename;
  PSFilename.appendSuffix("ps");

  sys::Path prog;

  // Set default grapher
#if HAVE_CIRCO
  prog = sys::Path(LLVM_PATH_CIRCO);
#endif
#if HAVE_TWOPI
  prog = sys::Path(LLVM_PATH_TWOPI);
#endif
#if HAVE_NEATO
  prog = sys::Path(LLVM_PATH_NEATO);
#endif
#if HAVE_FDP
  prog = sys::Path(LLVM_PATH_FDP);
#endif
#if HAVE_DOT
  prog = sys::Path(LLVM_PATH_DOT);
#endif

  // Find which program the user wants
#if HAVE_DOT
  if (program == GraphProgram::DOT)
    prog = sys::Path(LLVM_PATH_DOT);
#endif
#if (HAVE_FDP)
  if (program == GraphProgram::FDP)
    prog = sys::Path(LLVM_PATH_FDP);
#endif
#if (HAVE_NEATO)
  if (program == GraphProgram::NEATO)
    prog = sys::Path(LLVM_PATH_NEATO);
#endif
#if (HAVE_TWOPI)
  if (program == GraphProgram::TWOPI)
    prog = sys::Path(LLVM_PATH_TWOPI);
#endif
#if (HAVE_CIRCO)
  if (program == GraphProgram::CIRCO)
    prog = sys::Path(LLVM_PATH_CIRCO);
#endif

  std::vector<const char*> args;
  args.push_back(prog.c_str());
  args.push_back("-Tps");
  args.push_back("-Nfontname=Courier");
  args.push_back("-Gsize=7.5,10");
  args.push_back(Filename.c_str());
  args.push_back("-o");
  args.push_back(PSFilename.c_str());
  args.push_back(0);

  errs() << "Running '" << prog.str() << "' program... ";

  if (sys::Program::ExecuteAndWait(prog, &args[0], 0, 0, 0, 0, &ErrMsg)) {
     errs() << "Error viewing graph " << Filename.str() << ": '"
            << ErrMsg << "\n";
  } else {
    errs() << " done. \n";

    sys::Path gv(LLVM_PATH_GV);
    args.clear();
    args.push_back(gv.c_str());
    args.push_back(PSFilename.c_str());
    args.push_back("--spartan");
    args.push_back(0);

    ErrMsg.clear();
    if (wait) {
       if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg))
          errs() << "Error viewing graph: " << ErrMsg << "\n";
       Filename.eraseFromDisk();
       PSFilename.eraseFromDisk();
    }
    else {
       sys::Program::ExecuteNoWait(gv, &args[0],0,0,0,&ErrMsg);
       errs() << "Remember to erase graph files: " << Filename.str() << " "
              << PSFilename.str() << "\n";
    }
  }
#elif HAVE_DOTTY
  sys::Path dotty(LLVM_PATH_DOTTY);

  std::vector<const char*> args;
  args.push_back(dotty.c_str());
  args.push_back(Filename.c_str());
  args.push_back(0);

  errs() << "Running 'dotty' program... ";
  if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) {
     errs() << "Error viewing graph " << Filename.str() << ": "
            << ErrMsg << "\n";
  } else {
// Dotty spawns another app and doesn't wait until it returns
#if defined (__MINGW32__) || defined (_WINDOWS)
    return;
#endif
    Filename.eraseFromDisk();
  }
#endif
}
<|endoftext|>


<commit_before>//===- SystemUtils.cpp - Utilities for low-level system tasks -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions used to do a variety of low-level, often
// system-specific, tasks.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/SystemUtils.h"
#include "llvm/System/Program.h"
#include "llvm/Config/fcntl.h"
#include "llvm/Config/sys/wait.h"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <signal.h>

using namespace llvm;

/// isStandardOutAConsole - Return true if we can tell that the standard output
/// stream goes to a terminal window or console.
bool llvm::isStandardOutAConsole() {
#if HAVE_ISATTY
  return isatty(1);
#endif
  // If we don't have isatty, just return false.
  return false;
}

/// FindExecutable - Find a named executable, giving the argv[0] of program
/// being executed. This allows us to find another LLVM tool if it is built
/// into the same directory, but that directory is neither the current
/// directory, nor in the PATH.  If the executable cannot be found, return an
/// empty string.
///
#undef FindExecutable   // needed on windows :(
sys::Path llvm::FindExecutable(const std::string &ExeName,
                                 const std::string &ProgramPath) {
  // First check the directory that the calling program is in.  We can do this
  // if ProgramPath contains at least one / character, indicating that it is a
  // relative path to bugpoint itself.
  //
  sys::Path Result ( ProgramPath );
  Result.elideFile();

  if (!Result.isEmpty()) {
    Result.appendFile(ExeName);
    if (Result.executable()) return Result;
  }

  return sys::Program::FindProgramByName(ExeName);
}

static void RedirectFD(const std::string &File, int FD) {
  if (File.empty()) return;  // Noop

  // Open the file
  int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
  if (InFD == -1) {
    std::cerr << "Error opening file '" << File << "' for "
              << (FD == 0 ? "input" : "output") << "!\n";
    exit(1);
  }

  dup2(InFD, FD);   // Install it as the requested FD
  close(InFD);      // Close the original FD
}

static bool Timeout = false;
static void TimeOutHandler(int Sig) {
  Timeout = true;
}

/// RunProgramWithTimeout - This function executes the specified program, with
/// the specified null-terminated argument array, with the stdin/out/err fd's
/// redirected, with a timeout specified by the last argument.  This terminates
/// the calling program if there is an error executing the specified program.
/// It returns the return value of the program, or -1 if a timeout is detected.
///
int llvm::RunProgramWithTimeout(const std::string &ProgramPath,
                                const char **Args,
                                const std::string &StdInFile,
                                const std::string &StdOutFile,
                                const std::string &StdErrFile,
                                unsigned NumSeconds) {
#ifdef HAVE_SYS_WAIT_H
  int Child = fork();
  switch (Child) {
  case -1:
    std::cerr << "ERROR forking!\n";
    exit(1);
  case 0:               // Child
    RedirectFD(StdInFile, 0);      // Redirect file descriptors...
    RedirectFD(StdOutFile, 1);
    if (StdOutFile != StdErrFile)
      RedirectFD(StdErrFile, 2);
    else
      dup2(1, 2);

    execv(ProgramPath.c_str(), (char *const *)Args);
    std::cerr << "Error executing program: '" << ProgramPath;
    for (; *Args; ++Args)
      std::cerr << " " << *Args;
    std::cerr << "'\n";
    exit(1);

  default: break;
  }

  // Make sure all output has been written while waiting
  std::cout << std::flush;

  // Install a timeout handler.
  Timeout = false;
  struct sigaction Act, Old;
  Act.sa_sigaction = 0;
  Act.sa_handler = TimeOutHandler;
  sigemptyset(&Act.sa_mask);
  Act.sa_flags = 0;
  sigaction(SIGALRM, &Act, &Old);

  // Set the timeout if one is set.
  if (NumSeconds)
    alarm(NumSeconds);

  int Status;
  while (wait(&Status) != Child)
    if (errno == EINTR) {
      if (Timeout) {
        // Kill the child.
        kill(Child, SIGKILL);

        if (wait(&Status) != Child)
          std::cerr << "Something funny happened waiting for the child!\n";

        alarm(0);
        sigaction(SIGALRM, &Old, 0);
        return -1;   // Timeout detected
      } else {
        std::cerr << "Error waiting for child process!\n";
        exit(1);
      }
    }

  alarm(0);
  sigaction(SIGALRM, &Old, 0);
  return Status;

#else
  std::cerr << "RunProgramWithTimeout not implemented on this platform!\n";
  return -1;
#endif
}
<commit_msg>For PR351: * Remove unneeded header files. * Move RedirectFD static function to lib/System/Unix/Program.cpp * Delete RunProgramWithTimeout, now implemented by   sys::Program::ExecuteAndWait. RunProgramWithTimeout is now a convenience func.<commit_after>//===- SystemUtils.cpp - Utilities for low-level system tasks -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions used to do a variety of low-level, often
// system-specific, tasks.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/SystemUtils.h"
#include "llvm/System/Program.h"

using namespace llvm;

/// isStandardOutAConsole - Return true if we can tell that the standard output
/// stream goes to a terminal window or console.
bool llvm::isStandardOutAConsole() {
#if HAVE_ISATTY
  return isatty(1);
#endif
  // If we don't have isatty, just return false.
  return false;
}

/// FindExecutable - Find a named executable, giving the argv[0] of program
/// being executed. This allows us to find another LLVM tool if it is built
/// into the same directory, but that directory is neither the current
/// directory, nor in the PATH.  If the executable cannot be found, return an
/// empty string.
///
#undef FindExecutable   // needed on windows :(
sys::Path llvm::FindExecutable(const std::string &ExeName,
                               const std::string &ProgramPath) {
  // First check the directory that the calling program is in.  We can do this
  // if ProgramPath contains at least one / character, indicating that it is a
  // relative path to bugpoint itself.
  sys::Path Result ( ProgramPath );
  Result.elideFile();
  if (!Result.isEmpty()) {
    Result.appendFile(ExeName);
    if (Result.executable())
      return Result;
  }

  return sys::Program::FindProgramByName(ExeName);
}
<|endoftext|>


<commit_before>//===- lib/Trace/StateMovement.cpp ---------------------------------- C++ -===//
//
//
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

#include "seec/Trace/ProcessState.hpp"
#include "seec/Trace/StateMovement.hpp"
#include "seec/Trace/ThreadState.hpp"

#include <condition_variable>
#include <map>
#include <thread>
#include <vector>

namespace seec {

namespace trace {

/// \brief Implements state movement logic.
///
class ThreadedStateMovementHelper {
  /// Controls access to the ProcessState.
  std::mutex ProcessStateMutex;

  /// Used to wait for the ProcessState to update.
  std::condition_variable ProcessStateCV;

  /// Indicates that the movement has satisfied a predicate.
  std::atomic<bool> MovementComplete;

public:
  /// \name Constructors
  /// @{

  /// \brief Default constructor.
  ThreadedStateMovementHelper()
  : ProcessStateMutex(),
    ProcessStateCV(),
    MovementComplete(false)
  {}

  ThreadedStateMovementHelper(ThreadedStateMovementHelper const &) = delete;

  ThreadedStateMovementHelper(ThreadedStateMovementHelper &&) = delete;

  /// @}

  bool addNextEventBlock(ThreadState &State,
                         std::unique_lock<std::mutex> &UpdateLock) {
    auto const LastEvent = State.getTrace().events().end();
    auto const RewindNextEvent = State.getNextEvent();
    if (RewindNextEvent == LastEvent)
      return false;

    auto NextEvent = RewindNextEvent;

    while (true) {
      // Wait until the ProcessState reaches the appropriate process time
      // before we continue adding events.
      // If the event is just updating the local process time, then we must
      // wait until the ProcessState has reached this time. If the event will
      // set the ProcessState's time, then we must wait until the ProcessState
      // is at the time immediately prior to this new time.
      if (!UpdateLock) {
        auto MaybeNewProcessTime = NextEvent->getProcessTime();
        if (MaybeNewProcessTime.assigned()) {
          auto const &ProcState = State.getParent();
          auto const WaitUntil = NextEvent->modifiesSharedState()
                               ? MaybeNewProcessTime.get<0>() - 1
                               : MaybeNewProcessTime.get<0>();

          UpdateLock.lock();
          ProcessStateCV.wait(UpdateLock,
                              [=, &ProcState](){
                                return MovementComplete ||
                                       ProcState.getProcessTime() >= WaitUntil;
                              });

          if (MovementComplete) {
            // We can release the lock, because we'll only be rewinding local
            // changes. (If there were non-local changes in our rewinding area,
            // then we would already have owned the lock from applying them,
            // and thus would not be in this branch)
            UpdateLock.unlock();

            // Rewind changes.
            while (State.getNextEvent() != RewindNextEvent)
              State.removePreviousEvent();

            return false;
          }
        }
      }

      State.addNextEvent();

      NextEvent = State.getNextEvent();
      if (NextEvent->isBlockStart() || NextEvent == LastEvent)
        return true;
    }
  }

  bool addNextEventBlock(ThreadState &State) {
    std::unique_lock<std::mutex> UpdateLock(ProcessStateMutex, std::defer_lock);
    return addNextEventBlock(State, UpdateLock);
  }

  bool removePreviousEventBlock(ThreadState &State,
                                std::unique_lock<std::mutex> &UpdateLock) {
    auto const FirstEvent = State.getTrace().events().begin();
    auto const RewindNextEvent = State.getNextEvent();
    if (RewindNextEvent == FirstEvent)
      return false;

    auto PreviousEvent = RewindNextEvent;

    while (true) {
      --PreviousEvent;

      // Wait until the ProcessState reaches the appropriate process time
      // before we continue removing events.
      // If the event just updates the local process time, then we must wait
      // until the ProcessState has reached an earlier time. If the event will
      // set the ProcessState's time, then we must wait until the ProcessState
      // is at the time equal to the event's time (the removal of the event
      // will then cause the ProcessState to go to the next earliest time).
      if (!UpdateLock) {
        auto MaybeNewProcessTime = PreviousEvent->getProcessTime();
        if (MaybeNewProcessTime.assigned()) {
          auto const &ProcState = State.getParent();
          auto const WaitUntil = PreviousEvent->modifiesSharedState()
                               ? MaybeNewProcessTime.get<0>()
                               : MaybeNewProcessTime.get<0>() - 1;

          UpdateLock.lock();
          ProcessStateCV.wait(UpdateLock,
                              [=, &ProcState](){
                                return MovementComplete ||
                                       ProcState.getProcessTime() <= WaitUntil;
                              });

          if (MovementComplete) {
            // We can release the lock, because we'll only be rewinding local
            // changes. (If there were non-local changes in our rewinding area,
            // then we would already have owned the lock from applying them,
            // and thus would not be in this branch)
            UpdateLock.unlock();

            // Rewind changes.
            while (State.getNextEvent() != RewindNextEvent)
              State.addNextEvent();

            return false;
          }
        }
      }

      State.removePreviousEvent();

      if (PreviousEvent->isBlockStart() || PreviousEvent == FirstEvent)
        return true;

      PreviousEvent = State.getNextEvent();
    }
  }

  bool removePreviousEventBlock(ThreadState &State) {
    std::unique_lock<std::mutex> UpdateLock(ProcessStateMutex, std::defer_lock);
    return removePreviousEventBlock(State, UpdateLock);
  }

  bool moveForward(ProcessState &State,
                   ProcessPredTy &ProcessPredicate,
                   ThreadPredMapTy ThreadPredicates) {
    std::atomic<bool> Moved(false);
    std::vector<std::thread> Workers;

    for (auto &ThreadStatePtr : State.getThreadStates()) {
      auto const RawPtr = ThreadStatePtr.get();
      ThreadPredTy ThreadPred;

      // Get the thread-specific predicate, if one exists.
      auto const ThreadPredIt = ThreadPredicates.find(RawPtr);
      if (ThreadPredIt != ThreadPredicates.end())
        ThreadPred = ThreadPredIt->second;

      // Create a new worker thread to move this ThreadState.
      Workers.emplace_back([=, &State, &ProcessPredicate, &Moved](){
        // Thread worker code
        auto const LastEvent = RawPtr->getTrace().events().end();

        while (RawPtr->getNextEvent() != LastEvent) {
          // Add the next event block from this thread.
          std::unique_lock<std::mutex> Lock(ProcessStateMutex, std::defer_lock);
          if (addNextEventBlock(*RawPtr, Lock))
            Moved = true;

          // Check if another worker satisfied the movement.
          if (MovementComplete)
            break;

          // If the event acquired the shared process lock, then it might have
          // updated the ProcessState, in which case check the ProcessPredicate.
          if (Lock && ProcessPredicate && ProcessPredicate(State)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }

          // Check the thread-specific predicate, if one exists.
          if (ThreadPred && ThreadPred(*RawPtr)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }
        }
      });
    }

    // Wait for all thread workers to complete.
    for (auto &Worker : Workers) {
      Worker.join();
    }

    return Moved;
  }

  bool moveBackward(ProcessState &State,
                    ProcessPredTy &ProcessPredicate,
                    ThreadPredMapTy ThreadPredicates) {
    std::atomic<bool> Moved(false);
    std::vector<std::thread> Workers;

    for (auto &ThreadStatePtr : State.getThreadStates()) {
      auto RawPtr = ThreadStatePtr.get();
      ThreadPredTy ThreadPred;

      // Get the thread-specific predicate, if one exists.
      auto const ThreadPredIt = ThreadPredicates.find(RawPtr);
      if (ThreadPredIt != ThreadPredicates.end())
        ThreadPred = ThreadPredIt->second;

      // Create a new worker thread to move this ThreadState.
      Workers.emplace_back([=, &State, &ProcessPredicate, &Moved](){
        // Thread worker code
        auto const FirstEvent = RawPtr->getTrace().events().begin();

        while (RawPtr->getNextEvent() != FirstEvent) {
          // Add the next event block from this thread.
          std::unique_lock<std::mutex> Lock(ProcessStateMutex, std::defer_lock);
          if (removePreviousEventBlock(*RawPtr, Lock))
            Moved = true;

          // Check if another worker satisfied the movement.
          if (MovementComplete)
            break;

          // If the event acquired the shared process lock, then it might have
          // updated the ProcessState, in which case check the ProcessPredicate.
          if (Lock && ProcessPredicate(State)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }

          // Check the thread-specific predicate, if one exists.
          if (ThreadPred && ThreadPred(*RawPtr)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }
        }
      });
    }

    // Wait for all thread workers to complete.
    for (auto &Worker : Workers) {
      Worker.join();
    }

    return Moved;
  }
};

//===------------------------------------------------------------------------===
// ProcessState movement
//===------------------------------------------------------------------------===

bool moveForwardUntil(ProcessState &State,
                      ProcessPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveForward(State, Predicate, ThreadPredMapTy{});
}

bool moveBackwardUntil(ProcessState &State,
                       ProcessPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveBackward(State, Predicate, ThreadPredMapTy{});
}

bool moveForward(ProcessState &State) {
  auto const ProcessTime = State.getProcessTime();

  if (ProcessTime == State.getTrace().getFinalProcessTime())
    return false;

  return moveForwardUntil(State,
                          [=](ProcessState &NewState) -> bool {
                            return NewState.getProcessTime() > ProcessTime;
                          });
}

bool moveBackward(ProcessState &State) {
  auto const ProcessTime = State.getProcessTime();

  if (ProcessTime == 0)
    return false;

  return moveBackwardUntil(State,
                           [=](ProcessState &NewState){
                             return NewState.getProcessTime() < ProcessTime;
                           });
}

bool moveToTime(ProcessState &State, uint64_t const ProcessTime) {
  auto const PreviousTime = State.getProcessTime();

  if (PreviousTime < ProcessTime)
    return moveForwardUntil(State,
                            [=](ProcessState &NewState){
                              return NewState.getProcessTime() >= ProcessTime;
                            });
  else if (PreviousTime > ProcessTime)
    return moveBackwardUntil(State,
                             [=](ProcessState &NewState){
                               return NewState.getProcessTime() <= ProcessTime;
                             });

  return false;
}

//===------------------------------------------------------------------------===
// ThreadState movement
//===------------------------------------------------------------------------===

bool moveForwardUntil(ThreadState &State,
                      ThreadPredTy Predicate) {
  return false;
}

bool moveBackwardUntil(ThreadState &State,
                       ThreadPredTy Predicate) {
  return false;
}

bool moveForward(ThreadState &State) {
  return false;
}

bool moveBackward(ThreadState &State) {
  return false;
}

bool moveToTime(ThreadState &State, uint64_t ThreadTime) {
  if (State.getThreadTime() == ThreadTime)
    return false;

  ThreadedStateMovementHelper Mover;
  bool Moved = false;

  if (State.getThreadTime() < ThreadTime) {
    // Move forward
    auto LastEvent = State.getTrace().events().end();

    while (State.getThreadTime() < ThreadTime
           && State.getNextEvent() != LastEvent) {
      Mover.addNextEventBlock(State);
      Moved = true;
    }
  }
  else {
    // Move backward
    auto FirstEvent = State.getTrace().events().begin();

    while (State.getThreadTime() > ThreadTime
           && State.getNextEvent() != FirstEvent) {
      Mover.removePreviousEventBlock(State);
      Moved = true;
    }
  }

  return Moved;
}

} // namespace trace (in seec)

} // namespace seec
<commit_msg>Make thread movement use ThreadedStateMovementHelper with thread-specific predicates.<commit_after>//===- lib/Trace/StateMovement.cpp ---------------------------------- C++ -===//
//
//
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

#include "seec/Trace/ProcessState.hpp"
#include "seec/Trace/StateMovement.hpp"
#include "seec/Trace/ThreadState.hpp"

#include <condition_variable>
#include <initializer_list>
#include <map>
#include <thread>
#include <vector>

namespace seec {

namespace trace {

/// \brief Implements state movement logic.
///
class ThreadedStateMovementHelper {
  /// Controls access to the ProcessState.
  std::mutex ProcessStateMutex;

  /// Used to wait for the ProcessState to update.
  std::condition_variable ProcessStateCV;

  /// Indicates that the movement has satisfied a predicate.
  std::atomic<bool> MovementComplete;

public:
  /// \name Constructors
  /// @{

  /// \brief Default constructor.
  ThreadedStateMovementHelper()
  : ProcessStateMutex(),
    ProcessStateCV(),
    MovementComplete(false)
  {}

  ThreadedStateMovementHelper(ThreadedStateMovementHelper const &) = delete;

  ThreadedStateMovementHelper(ThreadedStateMovementHelper &&) = delete;

  /// @}

  bool addNextEventBlock(ThreadState &State,
                         std::unique_lock<std::mutex> &UpdateLock) {
    auto const LastEvent = State.getTrace().events().end();
    auto const RewindNextEvent = State.getNextEvent();
    if (RewindNextEvent == LastEvent)
      return false;

    auto NextEvent = RewindNextEvent;

    while (true) {
      // Wait until the ProcessState reaches the appropriate process time
      // before we continue adding events.
      // If the event is just updating the local process time, then we must
      // wait until the ProcessState has reached this time. If the event will
      // set the ProcessState's time, then we must wait until the ProcessState
      // is at the time immediately prior to this new time.
      if (!UpdateLock) {
        auto MaybeNewProcessTime = NextEvent->getProcessTime();
        if (MaybeNewProcessTime.assigned()) {
          auto const &ProcState = State.getParent();
          auto const WaitUntil = NextEvent->modifiesSharedState()
                               ? MaybeNewProcessTime.get<0>() - 1
                               : MaybeNewProcessTime.get<0>();

          UpdateLock.lock();
          ProcessStateCV.wait(UpdateLock,
                              [=, &ProcState](){
                                return MovementComplete ||
                                       ProcState.getProcessTime() >= WaitUntil;
                              });

          if (MovementComplete) {
            // We can release the lock, because we'll only be rewinding local
            // changes. (If there were non-local changes in our rewinding area,
            // then we would already have owned the lock from applying them,
            // and thus would not be in this branch)
            UpdateLock.unlock();

            // Rewind changes.
            while (State.getNextEvent() != RewindNextEvent)
              State.removePreviousEvent();

            return false;
          }
        }
      }

      State.addNextEvent();

      NextEvent = State.getNextEvent();
      if (NextEvent->isBlockStart() || NextEvent == LastEvent)
        return true;
    }
  }

  bool addNextEventBlock(ThreadState &State) {
    std::unique_lock<std::mutex> UpdateLock(ProcessStateMutex, std::defer_lock);
    return addNextEventBlock(State, UpdateLock);
  }

  bool removePreviousEventBlock(ThreadState &State,
                                std::unique_lock<std::mutex> &UpdateLock) {
    auto const FirstEvent = State.getTrace().events().begin();
    auto const RewindNextEvent = State.getNextEvent();
    if (RewindNextEvent == FirstEvent)
      return false;

    auto PreviousEvent = RewindNextEvent;

    while (true) {
      --PreviousEvent;

      // Wait until the ProcessState reaches the appropriate process time
      // before we continue removing events.
      // If the event just updates the local process time, then we must wait
      // until the ProcessState has reached an earlier time. If the event will
      // set the ProcessState's time, then we must wait until the ProcessState
      // is at the time equal to the event's time (the removal of the event
      // will then cause the ProcessState to go to the next earliest time).
      if (!UpdateLock) {
        auto MaybeNewProcessTime = PreviousEvent->getProcessTime();
        if (MaybeNewProcessTime.assigned()) {
          auto const &ProcState = State.getParent();
          auto const WaitUntil = PreviousEvent->modifiesSharedState()
                               ? MaybeNewProcessTime.get<0>()
                               : MaybeNewProcessTime.get<0>() - 1;

          UpdateLock.lock();
          ProcessStateCV.wait(UpdateLock,
                              [=, &ProcState](){
                                return MovementComplete ||
                                       ProcState.getProcessTime() <= WaitUntil;
                              });

          if (MovementComplete) {
            // We can release the lock, because we'll only be rewinding local
            // changes. (If there were non-local changes in our rewinding area,
            // then we would already have owned the lock from applying them,
            // and thus would not be in this branch)
            UpdateLock.unlock();

            // Rewind changes.
            while (State.getNextEvent() != RewindNextEvent)
              State.addNextEvent();

            return false;
          }
        }
      }

      State.removePreviousEvent();

      if (PreviousEvent->isBlockStart() || PreviousEvent == FirstEvent)
        return true;

      PreviousEvent = State.getNextEvent();
    }
  }

  bool removePreviousEventBlock(ThreadState &State) {
    std::unique_lock<std::mutex> UpdateLock(ProcessStateMutex, std::defer_lock);
    return removePreviousEventBlock(State, UpdateLock);
  }

  bool moveForward(ProcessState &State,
                   ProcessPredTy ProcessPredicate,
                   ThreadPredMapTy ThreadPredicates) {
    std::atomic<bool> Moved(false);
    std::vector<std::thread> Workers;

    for (auto &ThreadStatePtr : State.getThreadStates()) {
      auto const RawPtr = ThreadStatePtr.get();
      ThreadPredTy ThreadPred;

      // Get the thread-specific predicate, if one exists.
      auto const ThreadPredIt = ThreadPredicates.find(RawPtr);
      if (ThreadPredIt != ThreadPredicates.end())
        ThreadPred = ThreadPredIt->second;

      // Create a new worker thread to move this ThreadState.
      Workers.emplace_back([=, &State, &ProcessPredicate, &Moved](){
        // Thread worker code
        auto const LastEvent = RawPtr->getTrace().events().end();

        while (RawPtr->getNextEvent() != LastEvent) {
          // Add the next event block from this thread.
          std::unique_lock<std::mutex> Lock(ProcessStateMutex, std::defer_lock);
          if (addNextEventBlock(*RawPtr, Lock))
            Moved = true;

          // Check if another worker satisfied the movement.
          if (MovementComplete)
            break;

          // If the event acquired the shared process lock, then it might have
          // updated the ProcessState, in which case check the ProcessPredicate.
          if (Lock && ProcessPredicate && ProcessPredicate(State)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }

          // Check the thread-specific predicate, if one exists.
          if (ThreadPred && ThreadPred(*RawPtr)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }
        }
      });
    }

    // Wait for all thread workers to complete.
    for (auto &Worker : Workers) {
      Worker.join();
    }

    return Moved;
  }

  bool moveBackward(ProcessState &State,
                    ProcessPredTy ProcessPredicate,
                    ThreadPredMapTy ThreadPredicates) {
    std::atomic<bool> Moved(false);
    std::vector<std::thread> Workers;

    for (auto &ThreadStatePtr : State.getThreadStates()) {
      auto RawPtr = ThreadStatePtr.get();
      ThreadPredTy ThreadPred;

      // Get the thread-specific predicate, if one exists.
      auto const ThreadPredIt = ThreadPredicates.find(RawPtr);
      if (ThreadPredIt != ThreadPredicates.end())
        ThreadPred = ThreadPredIt->second;

      // Create a new worker thread to move this ThreadState.
      Workers.emplace_back([=, &State, &ProcessPredicate, &Moved](){
        // Thread worker code
        auto const FirstEvent = RawPtr->getTrace().events().begin();

        while (RawPtr->getNextEvent() != FirstEvent) {
          // Add the next event block from this thread.
          std::unique_lock<std::mutex> Lock(ProcessStateMutex, std::defer_lock);
          if (removePreviousEventBlock(*RawPtr, Lock))
            Moved = true;

          // Check if another worker satisfied the movement.
          if (MovementComplete)
            break;

          // If the event acquired the shared process lock, then it might have
          // updated the ProcessState, in which case check the ProcessPredicate.
          if (Lock && ProcessPredicate && ProcessPredicate(State)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }

          // Check the thread-specific predicate, if one exists.
          if (ThreadPred && ThreadPred(*RawPtr)) {
            MovementComplete = true;
            ProcessStateCV.notify_all();
            break;
          }
        }
      });
    }

    // Wait for all thread workers to complete.
    for (auto &Worker : Workers) {
      Worker.join();
    }

    return Moved;
  }
};

//===------------------------------------------------------------------------===
// ProcessState movement
//===------------------------------------------------------------------------===

bool moveForwardUntil(ProcessState &State,
                      ProcessPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveForward(State, Predicate, ThreadPredMapTy{});
}

bool moveBackwardUntil(ProcessState &State,
                       ProcessPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveBackward(State, Predicate, ThreadPredMapTy{});
}

bool moveForward(ProcessState &State) {
  auto const ProcessTime = State.getProcessTime();

  if (ProcessTime == State.getTrace().getFinalProcessTime())
    return false;

  return moveForwardUntil(State,
                          [=](ProcessState &NewState) -> bool {
                            return NewState.getProcessTime() > ProcessTime;
                          });
}

bool moveBackward(ProcessState &State) {
  auto const ProcessTime = State.getProcessTime();

  if (ProcessTime == 0)
    return false;

  return moveBackwardUntil(State,
                           [=](ProcessState &NewState){
                             return NewState.getProcessTime() < ProcessTime;
                           });
}

bool moveToTime(ProcessState &State, uint64_t const ProcessTime) {
  auto const PreviousTime = State.getProcessTime();

  if (PreviousTime < ProcessTime)
    return moveForwardUntil(State,
                            [=](ProcessState &NewState){
                              return NewState.getProcessTime() >= ProcessTime;
                            });
  else if (PreviousTime > ProcessTime)
    return moveBackwardUntil(State,
                             [=](ProcessState &NewState){
                               return NewState.getProcessTime() <= ProcessTime;
                             });

  return false;
}

//===------------------------------------------------------------------------===
// ThreadState movement
//===------------------------------------------------------------------------===

bool moveForwardUntil(ThreadState &State,
                      ThreadPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveForward(State.getParent(),
                           ProcessPredTy{},
                           ThreadPredMapTy{std::make_pair(&State, Predicate)});
}

bool moveBackwardUntil(ThreadState &State,
                       ThreadPredTy Predicate) {
  ThreadedStateMovementHelper Mover;
  return Mover.moveBackward(State.getParent(),
                            ProcessPredTy{},
                            ThreadPredMapTy{std::make_pair(&State, Predicate)});
}

bool moveForward(ThreadState &State) {
  return moveForwardUntil(State, [](ThreadState &){return true;});
}

bool moveBackward(ThreadState &State) {
  return moveBackwardUntil(State, [](ThreadState &){return true;});
}

bool moveToTime(ThreadState &State, uint64_t ThreadTime) {
  auto const PreviousTime = State.getThreadTime();

  if (PreviousTime < ThreadTime)
    return moveForwardUntil(State,
                            [=](ThreadState &NewState){
                              return NewState.getThreadTime() >= ThreadTime;
                            });
  else if (PreviousTime > ThreadTime)
    return moveBackwardUntil(State,
                             [=](ThreadState &NewState){
                               return NewState.getThreadTime() <= ThreadTime;
                             });

  return false;
}

} // namespace trace (in seec)

} // namespace seec
<|endoftext|>


<commit_before>//
//  Table.cpp
//
//
//  Created by James Spann on 3/28/14.
//
//

#include "Table.h"
#include "Variable.h"
#include "vm.h"

#define KBLU  "\x1B[34m"

int Svalues[40];
char Stypes[40];
int usedSpaces;//number of variables in table

using namespace std;

void SymbolTable::initializeTable(){
    usedSpaces = 0;
}

void SymbolTable::addToTable(char type,int v){
    if (usedSpaces < tableSpaces) {
        //type i=integer c=char
        //v is for value
        Stypes[usedSpaces] = type;
        Svalues[usedSpaces] = v;
        usedSpaces++;
    }else{
        badhalt("Cannot create new space in register");
    }

}

void SymbolTable::setValue(Variable loc, int vu){
    Svalues[loc.value] = vu;
}

void SymbolTable::printTable(){
    cout << "| Place | Type | Value |" << endl;
    for (int u = 0; u<usedSpaces; u++) {
        cout << "|   "<< u <<"   |  "<< Stypes[u] <<"   |   "<< Svalues[u] <<"   |" << endl;
    }
        cout << "|-------|------|-------|" << endl;
}

int SymbolTable::returnValues(int atLocation) {
    if (atLocation > 40 || atLocation < 0){
        cout << "Invalid memory location" << endl;
        return 0;
    }

    return Svalues[atLocation];
}<commit_msg>Gave a definition for maximum size of table<commit_after>//
//  Table.cpp
//
//
//  Created by James Spann on 3/28/14.
//
//

#include "Table.h"
#include "Variable.h"
#include "vm.h"

#define KBLU  "\x1B[34m"

int Svalues[40];
char Stypes[40];
int usedSpaces;//number of variables in table

using namespace std;

void SymbolTable::initializeTable(){
    usedSpaces = 0;
    tableSpaces = 40;
}

void SymbolTable::addToTable(char type,int v){
    if (usedSpaces < tableSpaces) {
        //type i=integer c=char
        //v is for value
        Stypes[usedSpaces] = type;
        Svalues[usedSpaces] = v;
        usedSpaces++;
    }else{
        badhalt("Cannot create new space in register");
    }

}

void SymbolTable::setValue(Variable loc, int vu){
    Svalues[loc.value] = vu;
}

void SymbolTable::printTable(){
    cout << "| Place | Type | Value |" << endl;
    for (int u = 0; u<usedSpaces; u++) {
        cout << "|   "<< u <<"   |  "<< Stypes[u] <<"   |   "<< Svalues[u] <<"   |" << endl;
    }
        cout << "|-------|------|-------|" << endl;
}

int SymbolTable::returnValues(int atLocation) {
    if (atLocation > 40 || atLocation < 0){
        cout << "Invalid memory location" << endl;
        return 0;
    }

    return Svalues[atLocation];
}<|endoftext|>


<commit_before>//===-- asan_malloc_mac.cc ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Mac-specific malloc interception.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC

#include "asan_interceptors.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"

using namespace __asan;
#define COMMON_MALLOC_ZONE_NAME "asan"
#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC)
#define COMMON_MALLOC_MALLOC(size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_malloc(size, &stack)
#define COMMON_MALLOC_REALLOC(ptr, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_realloc(ptr, size, &stack);
#define COMMON_MALLOC_CALLOC(count, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_calloc(count, size, &stack);
#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \
  GET_STACK_TRACE_MALLOC; \
  int res = asan_posix_memalign(memptr, alignment, size, &stack);
#define COMMON_MALLOC_VALLOC(size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
#define COMMON_MALLOC_FREE(ptr) \
  GET_STACK_TRACE_FREE; \
  asan_free(ptr, &stack, FROM_MALLOC);
#define COMMON_MALLOC_SIZE(ptr) \
  uptr size = asan_mz_size(ptr);
#define COMMON_MALLOC_FILL_STATS(zone, stats) \
  AsanMallocStats malloc_stats; \
  FillMallocStatistics(&malloc_stats); \
  CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \
  internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
  GET_STACK_TRACE_FREE; \
  ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
#define COMMON_MALLOC_NAMESPACE __asan
#define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0
#define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0

#include "sanitizer_common/sanitizer_malloc_mac.inc"

namespace COMMON_MALLOC_NAMESPACE {
bool HandleDlopenInit() {
  static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
  // We have no reliable way of knowing how we are being loaded
  // so make it a requirement on Apple platforms to set this environment
  // variable to indicate that we want to perform initialization via
  // dlopen().
  auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
  if (!init_str)
    return false;
  if (internal_strncmp(init_str, "1", 1) != 0)
    return false;
  // When we are loaded via `dlopen()` path we still initialize the malloc zone
  // so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
  // find an initialized malloc zone.
  InitMallocZoneFields();
  return true;
}
}  // namespace COMMON_MALLOC_NAMESPACE

#endif
<commit_msg>[ASan] On Darwin record global allocator pointer and size in introspection struct.<commit_after>//===-- asan_malloc_mac.cc ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Mac-specific malloc interception.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC

#include "asan_interceptors.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "lsan/lsan_common.h"

using namespace __asan;
#define COMMON_MALLOC_ZONE_NAME "asan"
#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC)
#define COMMON_MALLOC_MALLOC(size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_malloc(size, &stack)
#define COMMON_MALLOC_REALLOC(ptr, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_realloc(ptr, size, &stack);
#define COMMON_MALLOC_CALLOC(count, size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_calloc(count, size, &stack);
#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \
  GET_STACK_TRACE_MALLOC; \
  int res = asan_posix_memalign(memptr, alignment, size, &stack);
#define COMMON_MALLOC_VALLOC(size) \
  GET_STACK_TRACE_MALLOC; \
  void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
#define COMMON_MALLOC_FREE(ptr) \
  GET_STACK_TRACE_FREE; \
  asan_free(ptr, &stack, FROM_MALLOC);
#define COMMON_MALLOC_SIZE(ptr) \
  uptr size = asan_mz_size(ptr);
#define COMMON_MALLOC_FILL_STATS(zone, stats) \
  AsanMallocStats malloc_stats; \
  FillMallocStatistics(&malloc_stats); \
  CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \
  internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
  GET_STACK_TRACE_FREE; \
  ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
#define COMMON_MALLOC_NAMESPACE __asan
#define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0
#define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 1

#include "sanitizer_common/sanitizer_malloc_mac.inc"

namespace COMMON_MALLOC_NAMESPACE {

bool HandleDlopenInit() {
  static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
  // We have no reliable way of knowing how we are being loaded
  // so make it a requirement on Apple platforms to set this environment
  // variable to indicate that we want to perform initialization via
  // dlopen().
  auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
  if (!init_str)
    return false;
  if (internal_strncmp(init_str, "1", 1) != 0)
    return false;
  // When we are loaded via `dlopen()` path we still initialize the malloc zone
  // so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
  // find an initialized malloc zone.
  InitMallocZoneFields();
  return true;
}
}  // namespace COMMON_MALLOC_NAMESPACE

namespace {

void mi_extra_init(sanitizer_malloc_introspection_t *mi) {
  uptr last_byte_plus_one = 0;
  mi->allocator_ptr = 0;
  // Range is [begin_ptr, end_ptr)
  __lsan::GetAllocatorGlobalRange(&(mi->allocator_ptr), &last_byte_plus_one);
  CHECK_NE(mi->allocator_ptr, 0);
  CHECK_GT(last_byte_plus_one, mi->allocator_ptr);
  mi->allocator_size = last_byte_plus_one - (mi->allocator_ptr);
  CHECK_GT(mi->allocator_size, 0);
}
}  // namespace

#endif
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQNotes.cpp,v $
//   $Revision: 1.8 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2010/08/13 13:58:56 $
// End CVS Header

// Copyright (C) 2010 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QWebFrame>
#include <QProcess>

#include "CQNotes.h"
#include "CQIcons.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "model/CModelValue.h"
#include "model/CReaction.h"
#include "function/CFunction.h"
#include "report/CKeyFactory.h"
#include "copasi/report/CCopasiRootContainer.h"
#include "commandline/CConfigurationFile.h"

CQNotes::CQNotes(QWidget* parent, const char* name) :
    CopasiWidget(parent, name)
{
  setupUi(this);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::Edit));

  mpWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
}

CQNotes::~CQNotes()
{}

// virtual
bool CQNotes::update(ListViews::ObjectType /* objectType */, ListViews::Action action, const std::string & key)
{
  if (key == mKey &&
      action == ListViews::CHANGE)
    {
      load();
    }

  return true;
}

// virtual
bool CQNotes::leave()
{
  mpBtnToggleEdit->setFocus();
  save();

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  load();

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::View));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::Edit));
    }
}

void CQNotes::load()
{
  if (mpObject != NULL)
    {
      const std::string * pNotes = NULL;

      if (dynamic_cast< CModelEntity * >(mpObject))
        pNotes =
          &dynamic_cast< CModelEntity * >(mpObject)->getNotes();
      else if (dynamic_cast< CReaction * >(mpObject))
        pNotes =
          &dynamic_cast< CReaction * >(mpObject)->getNotes();
      else if (dynamic_cast< CFunction * >(mpObject))
        pNotes =
          &dynamic_cast< CFunction * >(mpObject)->getNotes();

      if (pNotes && *pNotes != "")
        {
          // The notes are UTF8 encoded however the html does not specify an encoding
          // thus Qt uses locale settings.
          mpWebView->setHtml(FROM_UTF8(*pNotes));
          mpEdit->setPlainText(FROM_UTF8(*pNotes));
        }
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  // TODO CRITICAL We need to validate that we have proper XML.
  // We can use QXmlSimpleReader for doing this as we are only interested the fact that
  // we have valid XML.

  if (mpObject != NULL)
    {
      const std::string * pNotes = NULL;

      if (dynamic_cast< CModelEntity * >(mpObject))
        pNotes =
          &static_cast< CModelEntity * >(mpObject)->getNotes();
      else if (dynamic_cast< CReaction * >(mpObject))
        pNotes =
          &static_cast< CReaction * >(mpObject)->getNotes();
      else if (dynamic_cast< CFunction * >(mpObject))
        pNotes =
          &static_cast< CFunction * >(mpObject)->getNotes();

      if (pNotes &&
          mpEdit->toPlainText() != FROM_UTF8(*pNotes))
        {
          if (dynamic_cast< CModelEntity * >(mpObject))
            static_cast< CModelEntity * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));

          /*
          else if (dynamic_cast< CReaction * >(mpObject))
            static_cast< CReaction * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));
          else if (dynamic_cast< CFunction * >(mpObject))
            static_cast< CFunction * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));
          */

          mChanged = true;
        }
    }

  if (mChanged)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);
    }

  mChanged = false;
  return;
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QString Commandline = FROM_UTF8(CCopasiRootContainer::getConfiguration()->getWebBrowser());

  if (Commandline == "")
    {
#ifdef Q_WS_MAC
      Commandline = "open %1";
#else
# ifdef Q_WS_WIN
      Commandline = "cmd /c start %1";
# else
      CQMessageBox::critical(this, "Unable to open link",
                             "COPASI requires you to specify an application for opening URLs for links to work.\n\nPlease go to the preferences and set an appropriate application in the format:\n  command [options] %1");

      return;
# endif  // Q_WS_WIN
#endif // Q_WS_MAC

      CCopasiRootContainer::getConfiguration()->setWebBrowser(TO_UTF8(Commandline));
    }

#ifdef Q_WS_WIN

  if (Commandline == "cmd /c start %1")
    {
      if (QProcess::execute(Commandline.arg(url.toString())) != 0)
        {
          CQMessageBox::critical(this, "Unable to open link",
                                 "COPASI requires you to specify an application for opening links. The currently provided command:\n  " +
                                 Commandline + "\nis not working properly.\n\nPlease go to the preferences and set an appropriate application in the format:\n  application [options] %1");
        }

      return;
    }

#endif // Q_WS_WIN

  if (!QProcess::startDetached(Commandline.arg(url.toString())))
    {
      CQMessageBox::critical(this, "Unable to open link",
                             "COPASI requires you to specify an application for opening links. The currently provided command:\n  " +
                             Commandline + "\nis not working properly.\n\nPlease go to the preferences and set an appropriate application in the format:\n  application [options] %1");
    }

  return;
}
<commit_msg>Fixed load().<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQNotes.cpp,v $
//   $Revision: 1.9 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2010/08/13 20:06:23 $
// End CVS Header

// Copyright (C) 2010 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QWebFrame>
#include <QProcess>

#include "CQNotes.h"
#include "CQIcons.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "model/CModelValue.h"
#include "model/CReaction.h"
#include "function/CFunction.h"
#include "report/CKeyFactory.h"
#include "copasi/report/CCopasiRootContainer.h"
#include "commandline/CConfigurationFile.h"

CQNotes::CQNotes(QWidget* parent, const char* name) :
    CopasiWidget(parent, name)
{
  setupUi(this);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::Edit));

  mpWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
}

CQNotes::~CQNotes()
{}

// virtual
bool CQNotes::update(ListViews::ObjectType /* objectType */, ListViews::Action action, const std::string & key)
{
  if (key == mKey &&
      action == ListViews::CHANGE)
    {
      load();
    }

  return true;
}

// virtual
bool CQNotes::leave()
{
  mpBtnToggleEdit->setFocus();
  save();

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  load();

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::View));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIcons::getIcon(CQIcons::Edit));
    }
}

void CQNotes::load()
{
  if (mpObject != NULL)
    {
      const std::string * pNotes = NULL;

      if (dynamic_cast< CModelEntity * >(mpObject))
        pNotes = &static_cast< CModelEntity * >(mpObject)->getNotes();
      else if (dynamic_cast< CReaction * >(mpObject))
        pNotes = &static_cast< CReaction * >(mpObject)->getNotes();
      else if (dynamic_cast< CFunction * >(mpObject))
        pNotes = &static_cast< CFunction * >(mpObject)->getNotes();

      if (pNotes != NULL)
        {
          // The notes are UTF8 encoded however the html does not specify an encoding
          // thus Qt uses locale settings.
          mpWebView->setHtml(FROM_UTF8(*pNotes));
          mpEdit->setPlainText(FROM_UTF8(*pNotes));
        }
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  // TODO CRITICAL We need to validate that we have proper XML.
  // We can use QXmlSimpleReader for doing this as we are only interested the fact that
  // we have valid XML.

  if (mpObject != NULL)
    {
      const std::string * pNotes = NULL;

      if (dynamic_cast< CModelEntity * >(mpObject))
        pNotes = &static_cast< CModelEntity * >(mpObject)->getNotes();
      else if (dynamic_cast< CReaction * >(mpObject))
        pNotes = &static_cast< CReaction * >(mpObject)->getNotes();
      else if (dynamic_cast< CFunction * >(mpObject))
        pNotes = &static_cast< CFunction * >(mpObject)->getNotes();

      if (pNotes &&
          mpEdit->toPlainText() != FROM_UTF8(*pNotes))
        {
          if (dynamic_cast< CModelEntity * >(mpObject))
            static_cast< CModelEntity * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));
          else if (dynamic_cast< CReaction * >(mpObject))
            static_cast< CReaction * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));
          else if (dynamic_cast< CFunction * >(mpObject))
            static_cast< CFunction * >(mpObject)->setNotes(TO_UTF8(mpEdit->toPlainText()));

          mChanged = true;
        }
    }

  if (mChanged)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);
    }

  mChanged = false;
  return;
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QString Commandline = FROM_UTF8(CCopasiRootContainer::getConfiguration()->getWebBrowser());

  if (Commandline == "")
    {
#ifdef Q_WS_MAC
      Commandline = "open %1";
#else
# ifdef Q_WS_WIN
      Commandline = "cmd /c start %1";
# else
      CQMessageBox::critical(this, "Unable to open link",
                             "COPASI requires you to specify an application for opening URLs for links to work.\n\nPlease go to the preferences and set an appropriate application in the format:\n  command [options] %1");

      return;
# endif  // Q_WS_WIN
#endif // Q_WS_MAC

      CCopasiRootContainer::getConfiguration()->setWebBrowser(TO_UTF8(Commandline));
    }

#ifdef Q_WS_WIN

  if (Commandline == "cmd /c start %1")
    {
      if (QProcess::execute(Commandline.arg(url.toString())) != 0)
        {
          CQMessageBox::critical(this, "Unable to open link",
                                 "COPASI requires you to specify an application for opening links. The currently provided command:\n  " +
                                 Commandline + "\nis not working properly.\n\nPlease go to the preferences and set an appropriate application in the format:\n  application [options] %1");
        }

      return;
    }

#endif // Q_WS_WIN

  if (!QProcess::startDetached(Commandline.arg(url.toString())))
    {
      CQMessageBox::critical(this, "Unable to open link",
                             "COPASI requires you to specify an application for opening links. The currently provided command:\n  " +
                             Commandline + "\nis not working properly.\n\nPlease go to the preferences and set an appropriate application in the format:\n  application [options] %1");
    }

  return;
}
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

#include <osquery/tables.h>

#if defined(__APPLE__)
#include <errno.h>
#include <sys/sysctl.h>
#include <time.h>
#elif defined(__linux__)
#include <sys/sysinfo.h>
#elif defined(WIN32)
#include <windows.h>
#endif

namespace osquery {
namespace tables {

long getUptime() {
#if defined(DARWIN)
  struct timeval boot_time;
  size_t len = sizeof(boot_time);
  int mib[2] = {CTL_KERN, KERN_BOOTTIME};

  if (sysctl(mib, 2, &boot_time, &len, nullptr, 0) < 0) {
    return -1;
  }

  time_t seconds_since_boot = boot_time.tv_sec;
  time_t current_seconds = time(nullptr);

  return long(difftime(current_seconds, seconds_since_boot));
#elif defined(__linux__)
  struct sysinfo sys_info;

  if (sysinfo(&sys_info) != 0) {
    return -1;
  }

  return sys_info.uptime;
#elif defined(WIN32)
  return static_cast<long>(GetTickCount64()) / 1000;
#endif

  return -1;
}

QueryData genUptime(QueryContext& context) {
  Row r;
  QueryData results;
  long uptime_in_seconds = getUptime();

  if (uptime_in_seconds >= 0) {
    r["days"] = INTEGER(uptime_in_seconds / 60 / 60 / 24);
    r["hours"] = INTEGER((uptime_in_seconds / 60 / 60) % 24);
    r["minutes"] = INTEGER((uptime_in_seconds / 60) % 60);
    r["seconds"] = INTEGER(uptime_in_seconds % 60);
    r["total_seconds"] = BIGINT(uptime_in_seconds);
    results.push_back(r);
  }

  return results;
}
} // namespace tables
} // namespace osquery
<commit_msg>fix incorrect uptime on windows (#4240)<commit_after>/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

#include <osquery/tables.h>

#if defined(__APPLE__)
#include <errno.h>
#include <sys/sysctl.h>
#include <time.h>
#elif defined(__linux__)
#include <sys/sysinfo.h>
#elif defined(WIN32)
#include <windows.h>
#endif

namespace osquery {
namespace tables {

long getUptime() {
#if defined(DARWIN)
  struct timeval boot_time;
  size_t len = sizeof(boot_time);
  int mib[2] = {CTL_KERN, KERN_BOOTTIME};

  if (sysctl(mib, 2, &boot_time, &len, nullptr, 0) < 0) {
    return -1;
  }

  time_t seconds_since_boot = boot_time.tv_sec;
  time_t current_seconds = time(nullptr);

  return long(difftime(current_seconds, seconds_since_boot));
#elif defined(__linux__)
  struct sysinfo sys_info;

  if (sysinfo(&sys_info) != 0) {
    return -1;
  }

  return sys_info.uptime;
#elif defined(WIN32)
  return static_cast<long>(GetTickCount64() / 1000);
#endif

  return -1;
}

QueryData genUptime(QueryContext& context) {
  Row r;
  QueryData results;
  long uptime_in_seconds = getUptime();

  if (uptime_in_seconds >= 0) {
    r["days"] = INTEGER(uptime_in_seconds / 60 / 60 / 24);
    r["hours"] = INTEGER((uptime_in_seconds / 60 / 60) % 24);
    r["minutes"] = INTEGER((uptime_in_seconds / 60) % 60);
    r["seconds"] = INTEGER(uptime_in_seconds % 60);
    r["total_seconds"] = BIGINT(uptime_in_seconds);
    results.push_back(r);
  }

  return results;
}
} // namespace tables
} // namespace osquery
<|endoftext|>


<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#define NOMINMAX
#include <windows.h>
#include "InputWin.h"
#include "core/Application.h"
#include "core/Engine.h"
#include "core/windows/WindowWin.h"
#include "events/EventDispatcher.h"
#include "GamepadWin.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace input
    {
        KeyboardKey InputWin::convertKeyCode(WPARAM wParam)
        {
            switch (wParam)
            {
                case VK_CANCEL: return KeyboardKey::CANCEL;
                case VK_BACK: return KeyboardKey::BACKSPACE;
                case VK_TAB: return KeyboardKey::TAB;
                case VK_CLEAR: return KeyboardKey::CLEAR;
                case VK_RETURN: return KeyboardKey::RETURN;
                case VK_SHIFT: return KeyboardKey::SHIFT;
                case VK_CONTROL: return KeyboardKey::CONTROL;
                case VK_MENU: return KeyboardKey::LALT;
                case VK_PAUSE: return KeyboardKey::PAUSE;
                case VK_CAPITAL: return KeyboardKey::CAPITAL;

                    // ... Japanese ...

                case VK_ESCAPE: return KeyboardKey::ESCAPE;

                    // ... IME ...

                case VK_SPACE: return KeyboardKey::SPACE;
                case VK_PRIOR: return KeyboardKey::PRIOR;
                case VK_NEXT: return KeyboardKey::NEXT;
                case VK_END: return KeyboardKey::END;
                case VK_HOME: return KeyboardKey::HOME;
                case VK_LEFT: return KeyboardKey::LEFT;
                case VK_UP: return KeyboardKey::UP;
                case VK_RIGHT: return KeyboardKey::RIGHT;
                case VK_DOWN: return KeyboardKey::DOWN;

                case VK_SELECT: return KeyboardKey::SELECT;
                case VK_PRINT: return KeyboardKey::PRINT;
                case VK_EXECUTE: return KeyboardKey::EXECUTE;

                case VK_SNAPSHOT: return KeyboardKey::SNAPSHOT;
                case VK_INSERT: return KeyboardKey::INSERT;
                case VK_DELETE: return KeyboardKey::DEL;
                case VK_HELP: return KeyboardKey::HELP;

                case '0': return KeyboardKey::KEY_0;
                case '1': return KeyboardKey::KEY_1;
                case '2': return KeyboardKey::KEY_2;
                case '3': return KeyboardKey::KEY_3;
                case '4': return KeyboardKey::KEY_4;
                case '5': return KeyboardKey::KEY_5;
                case '6': return KeyboardKey::KEY_6;
                case '7': return KeyboardKey::KEY_7;
                case '8': return KeyboardKey::KEY_8;
                case '9': return KeyboardKey::KEY_9;

                case 'A': return KeyboardKey::KEY_A;
                case 'B': return KeyboardKey::KEY_B;
                case 'C': return KeyboardKey::KEY_C;
                case 'D': return KeyboardKey::KEY_D;
                case 'E': return KeyboardKey::KEY_E;
                case 'F': return KeyboardKey::KEY_F;
                case 'G': return KeyboardKey::KEY_G;
                case 'H': return KeyboardKey::KEY_H;
                case 'I': return KeyboardKey::KEY_I;
                case 'J': return KeyboardKey::KEY_J;
                case 'K': return KeyboardKey::KEY_K;
                case 'L': return KeyboardKey::KEY_L;
                case 'M': return KeyboardKey::KEY_M;
                case 'N': return KeyboardKey::KEY_N;
                case 'O': return KeyboardKey::KEY_O;
                case 'P': return KeyboardKey::KEY_P;
                case 'Q': return KeyboardKey::KEY_Q;
                case 'R': return KeyboardKey::KEY_R;
                case 'S': return KeyboardKey::KEY_S;
                case 'T': return KeyboardKey::KEY_T;
                case 'U': return KeyboardKey::KEY_U;
                case 'V': return KeyboardKey::KEY_V;
                case 'W': return KeyboardKey::KEY_W;
                case 'X': return KeyboardKey::KEY_X;
                case 'Y': return KeyboardKey::KEY_Y;
                case 'Z': return KeyboardKey::KEY_Z;

                case VK_LWIN: return KeyboardKey::LSUPER;
                case VK_RWIN: return KeyboardKey::RSUPER;
                case VK_APPS: return KeyboardKey::APPS;
                case VK_SLEEP: return KeyboardKey::SLEEP;

                case VK_NUMPAD0: return KeyboardKey::NUMPAD0;
                case VK_NUMPAD1: return KeyboardKey::NUMPAD1;
                case VK_NUMPAD2: return KeyboardKey::NUMPAD2;
                case VK_NUMPAD3: return KeyboardKey::NUMPAD3;
                case VK_NUMPAD4: return KeyboardKey::NUMPAD4;
                case VK_NUMPAD5: return KeyboardKey::NUMPAD5;
                case VK_NUMPAD6: return KeyboardKey::NUMPAD6;
                case VK_NUMPAD7: return KeyboardKey::NUMPAD7;
                case VK_NUMPAD8: return KeyboardKey::NUMPAD8;
                case VK_NUMPAD9: return KeyboardKey::NUMPAD9;

                case VK_MULTIPLY: return KeyboardKey::MULTIPLY;
                case VK_ADD: return KeyboardKey::ADD;
                case VK_SEPARATOR: return KeyboardKey::SEPARATOR;
                case VK_SUBTRACT: return KeyboardKey::SUBTRACT;
                case VK_DECIMAL: return KeyboardKey::DECIMAL;
                case VK_DIVIDE: return KeyboardKey::DIVIDE;

                case VK_F1: return KeyboardKey::F1;
                case VK_F2: return KeyboardKey::F2;
                case VK_F3: return KeyboardKey::F3;
                case VK_F4: return KeyboardKey::F4;
                case VK_F5: return KeyboardKey::F5;
                case VK_F6: return KeyboardKey::F6;
                case VK_F7: return KeyboardKey::F7;
                case VK_F8: return KeyboardKey::F8;
                case VK_F9: return KeyboardKey::F9;
                case VK_F10: return KeyboardKey::F10;
                case VK_F11: return KeyboardKey::F11;
                case VK_F12: return KeyboardKey::F12;
                case VK_F13: return KeyboardKey::F13;
                case VK_F14: return KeyboardKey::F14;
                case VK_F15: return KeyboardKey::F15;
                case VK_F16: return KeyboardKey::F16;
                case VK_F17: return KeyboardKey::F17;
                case VK_F18: return KeyboardKey::F18;
                case VK_F19: return KeyboardKey::F19;
                case VK_F20: return KeyboardKey::F20;
                case VK_F21: return KeyboardKey::F21;
                case VK_F22: return KeyboardKey::F22;
                case VK_F23: return KeyboardKey::F23;
                case VK_F24: return KeyboardKey::F24;

                case VK_NUMLOCK: return KeyboardKey::NUMLOCK;
                case VK_SCROLL: return KeyboardKey::SCROLL;
                case VK_LSHIFT: return KeyboardKey::LSHIFT;
                case VK_RSHIFT: return KeyboardKey::RSHIFT;
                case VK_LCONTROL: return KeyboardKey::LCONTROL;
                case VK_RCONTROL: return KeyboardKey::RCONTROL;
                case VK_LMENU: return KeyboardKey::LALT;
                case VK_RMENU: return KeyboardKey::RALT;

                case VK_OEM_1: return KeyboardKey::SEMICOLON;
                case VK_OEM_PLUS: return KeyboardKey::PLUS;
                case VK_OEM_COMMA: return KeyboardKey::COMMA;
                case VK_OEM_MINUS: return KeyboardKey::MINUS;
                case VK_OEM_PERIOD: return KeyboardKey::PERIOD;
                case VK_OEM_2: return KeyboardKey::SLASH;
                case VK_OEM_3: return KeyboardKey::GRAVE;
                case VK_OEM_4: return KeyboardKey::BRACKET_LEFT;
                case VK_OEM_5: return KeyboardKey::BACKSLASH;
                case VK_OEM_6: return KeyboardKey::BRACKET_RIGHT;
                case VK_OEM_7: return KeyboardKey::QUOTE;
                case VK_OEM_8: return KeyboardKey::GRAVE;
                case VK_OEM_AX: return KeyboardKey::OEM_AX;
                case VK_OEM_102: return KeyboardKey::LESS;
            }
            return KeyboardKey::NONE;
        }

        uint32_t InputWin::getKeyboardModifiers(WPARAM wParam)
        {
            uint32_t modifiers = 0;

            if (wParam & MK_SHIFT) modifiers |= SHIFT_DOWN;
            if (wParam & MK_ALT) modifiers |= ALT_DOWN;
            if (wParam & MK_CONTROL) modifiers |= CONTROL_DOWN;

            return modifiers;
        }

        uint32_t InputWin::getMouseModifiers(WPARAM wParam)
        {
            uint32_t modifiers = 0;

            if (wParam & MK_SHIFT) modifiers |= SHIFT_DOWN;
            if (GetKeyState(VK_MENU) & 0x8000) modifiers |= ALT_DOWN;
            if (wParam & MK_CONTROL) modifiers |= CONTROL_DOWN;
            if (wParam & MK_LBUTTON) modifiers |= LEFT_MOUSE_DOWN;
            if (wParam & MK_RBUTTON) modifiers |= RIGHT_MOUSE_DOWN;
            if (wParam & MK_MBUTTON) modifiers |= MIDDLE_MOUSE_DOWN;

            return modifiers;
        }

        InputWin::InputWin()
        {
        }

        InputWin::~InputWin()
        {
        }

        void InputWin::update()
        {
            for (DWORD i = 0; i < XUSER_MAX_COUNT; ++i)
            {
                XINPUT_STATE state;

                memset(&state, 0, sizeof(XINPUT_STATE));

                DWORD result = XInputGetState(i, &state);

                if (result == ERROR_SUCCESS)
                {
                    if (!gamepads[i])
                    {
                        gamepads[i].reset(new GamepadWin(static_cast<int32_t>(i)));

                        Event event;
                        event.type = Event::Type::GAMEPAD_CONNECT;

                        event.gamepadEvent.gamepad = gamepads[i].get();

                        sharedEngine->getEventDispatcher()->postEvent(event);
                    }

                    gamepads[i]->update(state);
                }
                else if (result == ERROR_DEVICE_NOT_CONNECTED)
                {
                    if (gamepads[i])
                    {
                        Event event;
                        event.type = Event::Type::GAMEPAD_DISCONNECT;

                        event.gamepadEvent.gamepad = gamepads[i].get();

                        sharedEngine->getEventDispatcher()->postEvent(event);

                        gamepads[i].reset();
                    }
                }
                else
                {
                    Log(Log::Level::WARN) << "Failed to get state for gamepad " << i;
                }
            }
        }

        void InputWin::setCursorVisible(bool visible)
        {
            cursorVisible = visible;

            sharedApplication->execute([visible] {
                if (visible)
                {
                    SetCursor(LoadCursor(nullptr, IDC_ARROW));
                }
                else
                {
                    SetCursor(nullptr);
                }
            });
        }

        bool InputWin::isCursorVisible() const
        {
            return cursorVisible;
        }

        void InputApple::setCursorPosition(const Vector2& position)
        {
            Input::setCursorPosition(position);

            sharedApplication->execute([position] {
                POINT p;
                p.x = static_cast<LONG>(position.x);
                p.y = static_cast<LONG>(position.y);
                ClientToScreen(static_cast<WindowWin*>(sharedEngine->getWindow())->getNativeWindow(), &p);
                SetCursorPos(static_cast<int>(p.x),
                             static_cast<int>(p.y));
            });
        }
    } // namespace input
} // namespace ouzel
<commit_msg>Replace InputApple with InputWin<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#define NOMINMAX
#include <windows.h>
#include "InputWin.h"
#include "core/Application.h"
#include "core/Engine.h"
#include "core/windows/WindowWin.h"
#include "events/EventDispatcher.h"
#include "GamepadWin.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace input
    {
        KeyboardKey InputWin::convertKeyCode(WPARAM wParam)
        {
            switch (wParam)
            {
                case VK_CANCEL: return KeyboardKey::CANCEL;
                case VK_BACK: return KeyboardKey::BACKSPACE;
                case VK_TAB: return KeyboardKey::TAB;
                case VK_CLEAR: return KeyboardKey::CLEAR;
                case VK_RETURN: return KeyboardKey::RETURN;
                case VK_SHIFT: return KeyboardKey::SHIFT;
                case VK_CONTROL: return KeyboardKey::CONTROL;
                case VK_MENU: return KeyboardKey::LALT;
                case VK_PAUSE: return KeyboardKey::PAUSE;
                case VK_CAPITAL: return KeyboardKey::CAPITAL;

                    // ... Japanese ...

                case VK_ESCAPE: return KeyboardKey::ESCAPE;

                    // ... IME ...

                case VK_SPACE: return KeyboardKey::SPACE;
                case VK_PRIOR: return KeyboardKey::PRIOR;
                case VK_NEXT: return KeyboardKey::NEXT;
                case VK_END: return KeyboardKey::END;
                case VK_HOME: return KeyboardKey::HOME;
                case VK_LEFT: return KeyboardKey::LEFT;
                case VK_UP: return KeyboardKey::UP;
                case VK_RIGHT: return KeyboardKey::RIGHT;
                case VK_DOWN: return KeyboardKey::DOWN;

                case VK_SELECT: return KeyboardKey::SELECT;
                case VK_PRINT: return KeyboardKey::PRINT;
                case VK_EXECUTE: return KeyboardKey::EXECUTE;

                case VK_SNAPSHOT: return KeyboardKey::SNAPSHOT;
                case VK_INSERT: return KeyboardKey::INSERT;
                case VK_DELETE: return KeyboardKey::DEL;
                case VK_HELP: return KeyboardKey::HELP;

                case '0': return KeyboardKey::KEY_0;
                case '1': return KeyboardKey::KEY_1;
                case '2': return KeyboardKey::KEY_2;
                case '3': return KeyboardKey::KEY_3;
                case '4': return KeyboardKey::KEY_4;
                case '5': return KeyboardKey::KEY_5;
                case '6': return KeyboardKey::KEY_6;
                case '7': return KeyboardKey::KEY_7;
                case '8': return KeyboardKey::KEY_8;
                case '9': return KeyboardKey::KEY_9;

                case 'A': return KeyboardKey::KEY_A;
                case 'B': return KeyboardKey::KEY_B;
                case 'C': return KeyboardKey::KEY_C;
                case 'D': return KeyboardKey::KEY_D;
                case 'E': return KeyboardKey::KEY_E;
                case 'F': return KeyboardKey::KEY_F;
                case 'G': return KeyboardKey::KEY_G;
                case 'H': return KeyboardKey::KEY_H;
                case 'I': return KeyboardKey::KEY_I;
                case 'J': return KeyboardKey::KEY_J;
                case 'K': return KeyboardKey::KEY_K;
                case 'L': return KeyboardKey::KEY_L;
                case 'M': return KeyboardKey::KEY_M;
                case 'N': return KeyboardKey::KEY_N;
                case 'O': return KeyboardKey::KEY_O;
                case 'P': return KeyboardKey::KEY_P;
                case 'Q': return KeyboardKey::KEY_Q;
                case 'R': return KeyboardKey::KEY_R;
                case 'S': return KeyboardKey::KEY_S;
                case 'T': return KeyboardKey::KEY_T;
                case 'U': return KeyboardKey::KEY_U;
                case 'V': return KeyboardKey::KEY_V;
                case 'W': return KeyboardKey::KEY_W;
                case 'X': return KeyboardKey::KEY_X;
                case 'Y': return KeyboardKey::KEY_Y;
                case 'Z': return KeyboardKey::KEY_Z;

                case VK_LWIN: return KeyboardKey::LSUPER;
                case VK_RWIN: return KeyboardKey::RSUPER;
                case VK_APPS: return KeyboardKey::APPS;
                case VK_SLEEP: return KeyboardKey::SLEEP;

                case VK_NUMPAD0: return KeyboardKey::NUMPAD0;
                case VK_NUMPAD1: return KeyboardKey::NUMPAD1;
                case VK_NUMPAD2: return KeyboardKey::NUMPAD2;
                case VK_NUMPAD3: return KeyboardKey::NUMPAD3;
                case VK_NUMPAD4: return KeyboardKey::NUMPAD4;
                case VK_NUMPAD5: return KeyboardKey::NUMPAD5;
                case VK_NUMPAD6: return KeyboardKey::NUMPAD6;
                case VK_NUMPAD7: return KeyboardKey::NUMPAD7;
                case VK_NUMPAD8: return KeyboardKey::NUMPAD8;
                case VK_NUMPAD9: return KeyboardKey::NUMPAD9;

                case VK_MULTIPLY: return KeyboardKey::MULTIPLY;
                case VK_ADD: return KeyboardKey::ADD;
                case VK_SEPARATOR: return KeyboardKey::SEPARATOR;
                case VK_SUBTRACT: return KeyboardKey::SUBTRACT;
                case VK_DECIMAL: return KeyboardKey::DECIMAL;
                case VK_DIVIDE: return KeyboardKey::DIVIDE;

                case VK_F1: return KeyboardKey::F1;
                case VK_F2: return KeyboardKey::F2;
                case VK_F3: return KeyboardKey::F3;
                case VK_F4: return KeyboardKey::F4;
                case VK_F5: return KeyboardKey::F5;
                case VK_F6: return KeyboardKey::F6;
                case VK_F7: return KeyboardKey::F7;
                case VK_F8: return KeyboardKey::F8;
                case VK_F9: return KeyboardKey::F9;
                case VK_F10: return KeyboardKey::F10;
                case VK_F11: return KeyboardKey::F11;
                case VK_F12: return KeyboardKey::F12;
                case VK_F13: return KeyboardKey::F13;
                case VK_F14: return KeyboardKey::F14;
                case VK_F15: return KeyboardKey::F15;
                case VK_F16: return KeyboardKey::F16;
                case VK_F17: return KeyboardKey::F17;
                case VK_F18: return KeyboardKey::F18;
                case VK_F19: return KeyboardKey::F19;
                case VK_F20: return KeyboardKey::F20;
                case VK_F21: return KeyboardKey::F21;
                case VK_F22: return KeyboardKey::F22;
                case VK_F23: return KeyboardKey::F23;
                case VK_F24: return KeyboardKey::F24;

                case VK_NUMLOCK: return KeyboardKey::NUMLOCK;
                case VK_SCROLL: return KeyboardKey::SCROLL;
                case VK_LSHIFT: return KeyboardKey::LSHIFT;
                case VK_RSHIFT: return KeyboardKey::RSHIFT;
                case VK_LCONTROL: return KeyboardKey::LCONTROL;
                case VK_RCONTROL: return KeyboardKey::RCONTROL;
                case VK_LMENU: return KeyboardKey::LALT;
                case VK_RMENU: return KeyboardKey::RALT;

                case VK_OEM_1: return KeyboardKey::SEMICOLON;
                case VK_OEM_PLUS: return KeyboardKey::PLUS;
                case VK_OEM_COMMA: return KeyboardKey::COMMA;
                case VK_OEM_MINUS: return KeyboardKey::MINUS;
                case VK_OEM_PERIOD: return KeyboardKey::PERIOD;
                case VK_OEM_2: return KeyboardKey::SLASH;
                case VK_OEM_3: return KeyboardKey::GRAVE;
                case VK_OEM_4: return KeyboardKey::BRACKET_LEFT;
                case VK_OEM_5: return KeyboardKey::BACKSLASH;
                case VK_OEM_6: return KeyboardKey::BRACKET_RIGHT;
                case VK_OEM_7: return KeyboardKey::QUOTE;
                case VK_OEM_8: return KeyboardKey::GRAVE;
                case VK_OEM_AX: return KeyboardKey::OEM_AX;
                case VK_OEM_102: return KeyboardKey::LESS;
            }
            return KeyboardKey::NONE;
        }

        uint32_t InputWin::getKeyboardModifiers(WPARAM wParam)
        {
            uint32_t modifiers = 0;

            if (wParam & MK_SHIFT) modifiers |= SHIFT_DOWN;
            if (wParam & MK_ALT) modifiers |= ALT_DOWN;
            if (wParam & MK_CONTROL) modifiers |= CONTROL_DOWN;

            return modifiers;
        }

        uint32_t InputWin::getMouseModifiers(WPARAM wParam)
        {
            uint32_t modifiers = 0;

            if (wParam & MK_SHIFT) modifiers |= SHIFT_DOWN;
            if (GetKeyState(VK_MENU) & 0x8000) modifiers |= ALT_DOWN;
            if (wParam & MK_CONTROL) modifiers |= CONTROL_DOWN;
            if (wParam & MK_LBUTTON) modifiers |= LEFT_MOUSE_DOWN;
            if (wParam & MK_RBUTTON) modifiers |= RIGHT_MOUSE_DOWN;
            if (wParam & MK_MBUTTON) modifiers |= MIDDLE_MOUSE_DOWN;

            return modifiers;
        }

        InputWin::InputWin()
        {
        }

        InputWin::~InputWin()
        {
        }

        void InputWin::update()
        {
            for (DWORD i = 0; i < XUSER_MAX_COUNT; ++i)
            {
                XINPUT_STATE state;

                memset(&state, 0, sizeof(XINPUT_STATE));

                DWORD result = XInputGetState(i, &state);

                if (result == ERROR_SUCCESS)
                {
                    if (!gamepads[i])
                    {
                        gamepads[i].reset(new GamepadWin(static_cast<int32_t>(i)));

                        Event event;
                        event.type = Event::Type::GAMEPAD_CONNECT;

                        event.gamepadEvent.gamepad = gamepads[i].get();

                        sharedEngine->getEventDispatcher()->postEvent(event);
                    }

                    gamepads[i]->update(state);
                }
                else if (result == ERROR_DEVICE_NOT_CONNECTED)
                {
                    if (gamepads[i])
                    {
                        Event event;
                        event.type = Event::Type::GAMEPAD_DISCONNECT;

                        event.gamepadEvent.gamepad = gamepads[i].get();

                        sharedEngine->getEventDispatcher()->postEvent(event);

                        gamepads[i].reset();
                    }
                }
                else
                {
                    Log(Log::Level::WARN) << "Failed to get state for gamepad " << i;
                }
            }
        }

        void InputWin::setCursorVisible(bool visible)
        {
            cursorVisible = visible;

            sharedApplication->execute([visible] {
                if (visible)
                {
                    SetCursor(LoadCursor(nullptr, IDC_ARROW));
                }
                else
                {
                    SetCursor(nullptr);
                }
            });
        }

        bool InputWin::isCursorVisible() const
        {
            return cursorVisible;
        }

        void InputWin::setCursorPosition(const Vector2& position)
        {
            Input::setCursorPosition(position);

            sharedApplication->execute([position] {
                POINT p;
                p.x = static_cast<LONG>(position.x);
                p.y = static_cast<LONG>(position.y);
                ClientToScreen(static_cast<WindowWin*>(sharedEngine->getWindow())->getNativeWindow(), &p);
                SetCursorPos(static_cast<int>(p.x),
                             static_cast<int>(p.y));
            });
        }
    } // namespace input
} // namespace ouzel
<|endoftext|>


<commit_before>#ifndef SILICIUM_REACTIVE_TUPLE_HPP
#define SILICIUM_REACTIVE_TUPLE_HPP

#include <silicium/observable.hpp>
#include <silicium/config.hpp>
#include <silicium/detail/integer_sequence.hpp>
#include <bitset>

namespace Si
{
#ifdef _MSC_VER
#	define SILICIUM_RX_TUPLE_AVAILABLE 0
#else
#	define SILICIUM_RX_TUPLE_AVAILABLE 1
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	template <class ...Parts>
	struct and_combinator : observable<std::tuple<typename Parts::element_type...>>
	{
		typedef std::tuple<Parts...> parts_tuple;
		typedef std::tuple<typename Parts::element_type...> buffer_tuple;

		template <class PartsTuple>
		explicit and_combinator(PartsTuple &&parts)
			: parts(std::forward<PartsTuple>(parts))
		{
		}

		virtual void async_get_one(observer<buffer_tuple> &receiver) SILICIUM_OVERRIDE
		{
			assert(!this->receiver);
			this->receiver = &receiver;
			this->elements_received.reset();
			return async_get_one_impl<0, Parts...>();
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			return cancel_impl<0, Parts...>();
		}

	private:

		template <class Element, std::size_t Index>
		struct tuple_observer : observer<Element>
		{
			and_combinator *combinator = nullptr;

			virtual void got_element(Element value) SILICIUM_OVERRIDE
			{
				std::get<Index>(combinator->buffer) = std::move(value);
				combinator->elements_received.set(Index);
				combinator->check_received();
			}

			virtual void ended() SILICIUM_OVERRIDE
			{
				auto *receiver_copy = combinator->receiver;
				combinator->receiver = nullptr;
				receiver_copy->ended();
			}
		};

		template <class Indices>
		struct make_observers;

		template <std::size_t ...I>
		struct make_observers<ranges::v3::integer_sequence<I...>>
		{
			typedef std::tuple<tuple_observer<typename Parts::element_type, I>...> type;
		};

		typedef typename make_observers<typename ranges::v3::make_integer_sequence<sizeof...(Parts)>::type>::type observers_type;

		parts_tuple parts;
		observer<buffer_tuple> *receiver = nullptr;
		buffer_tuple buffer;
		std::bitset<sizeof...(Parts)> elements_received;
		observers_type observers;

		template <std::size_t Index, class Head, class ...Tail>
		void async_get_one_impl()
		{
			auto &observer = std::get<Index>(observers);
			observer.combinator = this;
			auto &part = std::get<Index>(parts);
			part.async_get_one(observer);
			return async_get_one_impl<Index + 1, Tail...>();
		}

		template <std::size_t Index>
		void async_get_one_impl()
		{
		}

		template <std::size_t Index, class Head, class ...Tail>
		void cancel_impl()
		{
			assert(receiver);
			auto &part = std::get<Index>(parts);
			part.cancel();
			return cancel_impl<Index + 1, Tail...>();
		}

		template <std::size_t Index>
		void cancel_impl()
		{
		}

		void check_received()
		{
			if (!elements_received.all())
			{
				return;
			}

			auto *receiver_copy = receiver;
			receiver = nullptr;
			receiver_copy->got_element(std::move(buffer));
		}
	};

	template <class ...Parts>
	auto make_tuple(Parts &&...parts) -> and_combinator<typename std::decay<Parts>::type...>
	{
		return and_combinator<typename std::decay<Parts>::type...>(std::make_tuple(std::forward<Parts>(parts)...));
	}
#endif
}

#endif
<commit_msg>implement move operations for tuple observable<commit_after>#ifndef SILICIUM_REACTIVE_TUPLE_HPP
#define SILICIUM_REACTIVE_TUPLE_HPP

#include <silicium/observable.hpp>
#include <silicium/config.hpp>
#include <silicium/detail/integer_sequence.hpp>
#include <bitset>

namespace Si
{
#ifdef _MSC_VER
#	define SILICIUM_RX_TUPLE_AVAILABLE 0
#else
#	define SILICIUM_RX_TUPLE_AVAILABLE 1
#endif

#if SILICIUM_RX_TUPLE_AVAILABLE
	template <class ...Parts>
	struct and_combinator : observable<std::tuple<typename Parts::element_type...>>
	{
		typedef std::tuple<Parts...> parts_tuple;
		typedef std::tuple<typename Parts::element_type...> buffer_tuple;

		template <class PartsTuple>
		explicit and_combinator(PartsTuple &&parts)
			: parts(std::forward<PartsTuple>(parts))
		{
		}

#if !SILICIUM_COMPILER_GENERATES_MOVES
		and_combinator(and_combinator &&other)
			: parts(std::move(other.parts))
			, receiver(std::move(other.receiver))
			, buffer(std::move(other.buffer))
			, elements_received(std::move(other.elements_received))
			, observers(std::move(other.observers))
		{
		}

		and_combinator &operator = (and_combinator &&other)
		{
			parts = std::move(other.parts);
			receiver = std::move(other.receiver);
			buffer = std::move(other.buffer);
			elements_received = std::move(other.elements_received);
			observers = std::move(other.observers);
			return *this;
		}
#endif

		virtual void async_get_one(observer<buffer_tuple> &receiver) SILICIUM_OVERRIDE
		{
			assert(!this->receiver);
			this->receiver = &receiver;
			this->elements_received.reset();
			return async_get_one_impl<0, Parts...>();
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			return cancel_impl<0, Parts...>();
		}

	private:

		template <class Element, std::size_t Index>
		struct tuple_observer : observer<Element>
		{
			and_combinator *combinator = nullptr;

			virtual void got_element(Element value) SILICIUM_OVERRIDE
			{
				std::get<Index>(combinator->buffer) = std::move(value);
				combinator->elements_received.set(Index);
				combinator->check_received();
			}

			virtual void ended() SILICIUM_OVERRIDE
			{
				auto *receiver_copy = combinator->receiver;
				combinator->receiver = nullptr;
				receiver_copy->ended();
			}
		};

		template <class Indices>
		struct make_observers;

		template <std::size_t ...I>
		struct make_observers<ranges::v3::integer_sequence<I...>>
		{
			typedef std::tuple<tuple_observer<typename Parts::element_type, I>...> type;
		};

		typedef typename make_observers<typename ranges::v3::make_integer_sequence<sizeof...(Parts)>::type>::type observers_type;

		parts_tuple parts;
		observer<buffer_tuple> *receiver = nullptr;
		buffer_tuple buffer;
		std::bitset<sizeof...(Parts)> elements_received;
		observers_type observers;

		template <std::size_t Index, class Head, class ...Tail>
		void async_get_one_impl()
		{
			auto &observer = std::get<Index>(observers);
			observer.combinator = this;
			auto &part = std::get<Index>(parts);
			part.async_get_one(observer);
			return async_get_one_impl<Index + 1, Tail...>();
		}

		template <std::size_t Index>
		void async_get_one_impl()
		{
		}

		template <std::size_t Index, class Head, class ...Tail>
		void cancel_impl()
		{
			assert(receiver);
			auto &part = std::get<Index>(parts);
			part.cancel();
			return cancel_impl<Index + 1, Tail...>();
		}

		template <std::size_t Index>
		void cancel_impl()
		{
		}

		void check_received()
		{
			if (!elements_received.all())
			{
				return;
			}

			auto *receiver_copy = receiver;
			receiver = nullptr;
			receiver_copy->got_element(std::move(buffer));
		}
	};

	template <class ...Parts>
	auto make_tuple(Parts &&...parts) -> and_combinator<typename std::decay<Parts>::type...>
	{
		return and_combinator<typename std::decay<Parts>::type...>(std::make_tuple(std::forward<Parts>(parts)...));
	}
#endif
}

#endif
<|endoftext|>