<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: c_dealer.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 16:47:59 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <precomp.h>
#include "c_dealer.hxx"

// NOT FULLY DECLARED SERVICES
#include <ary/cpp/c_gate.hxx>
#include <ary/loc/locp_le.hxx>
#include <ary/loc/loc_root.hxx>
#include <ary/loc/loc_file.hxx>
//#include <ary/docu.hxx>
#include <adoc/a_rdocu.hxx>
#include "all_toks.hxx"
#include "c_rcode.hxx"

namespace ary
{
namespace loc
{
    class Root;
}
}

namespace cpp
{

Distributor::Distributor( ary::cpp::Gate & io_rAryGate )
    :   aCppPreProcessor(),
        aCodeExplorer(io_rAryGate),
        aDocuExplorer(),
        pGate(&io_rAryGate),
        pFileEventHandler(0),
        pDocuDistributor(0)
{
    pFileEventHandler = & aCodeExplorer.FileEventHandler();
    pDocuDistributor = & aCodeExplorer.DocuDistributor();
}

void
Distributor::AssignPartners( CharacterSource &   io_rSourceText,
                             const MacroMap &    i_rValidMacros )
{
    aCppPreProcessor.AssignPartners(aCodeExplorer, io_rSourceText, i_rValidMacros);
}

Distributor::~Distributor()
{
}

void
Distributor::StartNewFile( const csv::ploc::Path & i_file )
{
    const csv::ploc::Root &
        root_dir = i_file.RootDir();
    StreamLock
        sl(700);
    root_dir.Get(sl());
    csv::ploc::Path
        root_path( sl().c_str(), true );
    ary::loc::Le_id
        root_id = pGate->Locations().CheckIn_Root(root_path).LeId();
    ary::loc::File &
        rFile = pGate->Locations().CheckIn_File(
                                        i_file.File(),
                                        i_file.DirChain(),
                                        root_id  );
    pFileEventHandler->SetCurFile(rFile);

    aCodeExplorer.StartNewFile();

    csv_assert( pDocuDistributor != 0 );
    aDocuExplorer.StartNewFile(*pDocuDistributor);
}

void
Distributor::Deal_Eol()
{
    pFileEventHandler->Event_IncrLineCount();
}

void
Distributor::Deal_Eof()
{
    // Do nothing yet.
}

void
Distributor::Deal_Cpp_UnblockMacro( Tok_UnblockMacro & let_drToken )
{
    aCppPreProcessor.UnblockMacro(let_drToken.Text());
    delete &let_drToken;
}

void
Distributor::Deal_CppCode( cpp::Token & let_drToken )
{
    aCppPreProcessor.Process_Token(let_drToken);
}

void
Distributor::Deal_AdcDocu( adoc::Token & let_drToken )
{
    aDocuExplorer.Process_Token(let_drToken);
}

Distributor *
Distributor::AsDistributor()
{
     return this;
}

}   // namespace cpp

<commit_msg>INTEGRATION: CWS changefileheader (1.7.22); FILE MERGED 2008/03/28 16:02:22 rt 1.7.22.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: c_dealer.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <precomp.h>
#include "c_dealer.hxx"

// NOT FULLY DECLARED SERVICES
#include <ary/cpp/c_gate.hxx>
#include <ary/loc/locp_le.hxx>
#include <ary/loc/loc_root.hxx>
#include <ary/loc/loc_file.hxx>
//#include <ary/docu.hxx>
#include <adoc/a_rdocu.hxx>
#include "all_toks.hxx"
#include "c_rcode.hxx"

namespace ary
{
namespace loc
{
    class Root;
}
}

namespace cpp
{

Distributor::Distributor( ary::cpp::Gate & io_rAryGate )
    :   aCppPreProcessor(),
        aCodeExplorer(io_rAryGate),
        aDocuExplorer(),
        pGate(&io_rAryGate),
        pFileEventHandler(0),
        pDocuDistributor(0)
{
    pFileEventHandler = & aCodeExplorer.FileEventHandler();
    pDocuDistributor = & aCodeExplorer.DocuDistributor();
}

void
Distributor::AssignPartners( CharacterSource &   io_rSourceText,
                             const MacroMap &    i_rValidMacros )
{
    aCppPreProcessor.AssignPartners(aCodeExplorer, io_rSourceText, i_rValidMacros);
}

Distributor::~Distributor()
{
}

void
Distributor::StartNewFile( const csv::ploc::Path & i_file )
{
    const csv::ploc::Root &
        root_dir = i_file.RootDir();
    StreamLock
        sl(700);
    root_dir.Get(sl());
    csv::ploc::Path
        root_path( sl().c_str(), true );
    ary::loc::Le_id
        root_id = pGate->Locations().CheckIn_Root(root_path).LeId();
    ary::loc::File &
        rFile = pGate->Locations().CheckIn_File(
                                        i_file.File(),
                                        i_file.DirChain(),
                                        root_id  );
    pFileEventHandler->SetCurFile(rFile);

    aCodeExplorer.StartNewFile();

    csv_assert( pDocuDistributor != 0 );
    aDocuExplorer.StartNewFile(*pDocuDistributor);
}

void
Distributor::Deal_Eol()
{
    pFileEventHandler->Event_IncrLineCount();
}

void
Distributor::Deal_Eof()
{
    // Do nothing yet.
}

void
Distributor::Deal_Cpp_UnblockMacro( Tok_UnblockMacro & let_drToken )
{
    aCppPreProcessor.UnblockMacro(let_drToken.Text());
    delete &let_drToken;
}

void
Distributor::Deal_CppCode( cpp::Token & let_drToken )
{
    aCppPreProcessor.Process_Token(let_drToken);
}

void
Distributor::Deal_AdcDocu( adoc::Token & let_drToken )
{
    aDocuExplorer.Process_Token(let_drToken);
}

Distributor *
Distributor::AsDistributor()
{
     return this;
}

}   // namespace cpp

<|endoftext|>


<commit_before>#include <xzero/executor/NativeScheduler.h>
#include <xzero/RuntimeError.h>
#include <xzero/WallClock.h>
#include <xzero/sysconfig.h>
#include <algorithm>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>

namespace xzero {

#define PIPE_READ_END  0
#define PIPE_WRITE_END 1

/**
 * XXX
 * - registering a key should be *ONESHOT* and *Edge Triggered*
 * - remove SelectionKey::change()
 * - add SelectionKey::cancel()
 * - do we need Selectable then (just use EndPoinit or `int fd`?)
 *   - endpoint: operator int() { return handle(); }
 * - maybe inherit from Executor
 * - add a way to add timed callbacks that can be cancelled
 * - actual implementations inheriting from: Selector < Scheduler < Executor
 * - select: SelectEventLoop (currently: NativeScheduler)
 * - epoll: LinuxEventLoop
 *
 */

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock,
    std::function<void()> preInvoke,
    std::function<void()> postInvoke)
    : Scheduler(std::move(errorLogger)),
      clock_(clock ? clock : WallClock::system()),
      onPreInvokePending_(preInvoke),
      onPostInvokePending_(postInvoke),
      lock_(),
      wakeupPipe_() {
  if (pipe(wakeupPipe_) < 0) {
    throw SYSTEM_ERROR(errno);
  }
  fcntl(wakeupPipe_[0], F_SETFL, O_NONBLOCK);
  fcntl(wakeupPipe_[1], F_SETFL, O_NONBLOCK);
}

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock)
    : NativeScheduler(errorLogger, clock, nullptr, nullptr) {
}

NativeScheduler::NativeScheduler()
    : NativeScheduler(nullptr, nullptr, nullptr, nullptr) {
}

NativeScheduler::~NativeScheduler() {
  ::close(wakeupPipe_[PIPE_READ_END]);
  ::close(wakeupPipe_[PIPE_WRITE_END]);
}

void NativeScheduler::execute(Task&& task) {
  {
    std::lock_guard<std::mutex> lk(lock_);
    tasks_.push_back(task);
  }
  breakLoop();
}

std::string NativeScheduler::toString() const {
  return "NativeScheduler";
}

Scheduler::HandleRef NativeScheduler::executeAfter(TimeSpan delay, Task task) {
  auto onFire = [task]() {
    task();
  };

  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  return insertIntoTimersList(clock_->get() + delay,
                              std::make_shared<Handle>(onFire, onCancel));
}

Scheduler::HandleRef NativeScheduler::executeAt(DateTime when, Task task) {
  auto onFire = [task]() {
    task();
  };

  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  return insertIntoTimersList(when, std::make_shared<Handle>(onFire, onCancel));
}

TimeSpan NativeScheduler::computeNextTimeout() {
  std::lock_guard<std::mutex> lk(lock_);

  return timers_.empty()
    ? timers_.front().when - clock_->get()
    : TimeSpan::fromSeconds(4);
}

Scheduler::HandleRef NativeScheduler::insertIntoTimersList(DateTime dt,
                                                           HandleRef handle) {
  Timer t = { dt, handle };

  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.end();
  auto e = timers_.begin();

  while (i != e) {
    i--;
    const Timer& current = *i;
    if (current.when >= t.when) {
      timers_.insert(i, t);
      return handle;
    }
  }

  if (i == e) {
    timers_.push_front(t);
  }

  return handle;
}

void NativeScheduler::removeFromTimersList(Handle* handle) {
  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.begin();
  auto e = timers_.end();

  while (i != e) {
    if (i->handle.get() == handle) {
      timers_.erase(i);
      break;
    }
    i++;
  }
}

void NativeScheduler::collectTimeouts() {
  const DateTime now = clock_->get();

  std::lock_guard<std::mutex> lk(lock_);

  for (;;) {
    if (timers_.empty())
      break;

    const Timer& job = timers_.front();

    if (job.when > now)
      break;

    tasks_.push_back(job.handle->getAction());
    timers_.pop_front();
  }
}

inline Scheduler::HandleRef registerInterest(
    std::mutex* registryLock,
    std::list<std::pair<int, Scheduler::HandleRef>>* registry,
    int fd,
    Executor::Task task) {

  auto onCancel = [=](Scheduler::Handle* h) {
    std::lock_guard<std::mutex> lk(*registryLock);
    for (auto i: *registry) {
      if (i.second.get() == h) {
        return registry->remove(i);
      }
    }
  };

  std::lock_guard<std::mutex> lk(*registryLock);
  auto handle = std::make_shared<Scheduler::Handle>(task, onCancel);
  registry->push_back(std::make_pair(fd, handle));

  return handle;
}

Scheduler::HandleRef NativeScheduler::executeOnReadable(int fd, Task task) {
  return registerInterest(&lock_, &readers_, fd, task);
}

Scheduler::HandleRef NativeScheduler::executeOnWritable(int fd, Task task) {
  return registerInterest(&lock_, &writers_, fd, task);
}

inline void collectActiveHandles(
    std::list<std::pair<int, Scheduler::HandleRef>>* interests,
    fd_set* fdset,
    std::vector<Scheduler::HandleRef>* result) {

  auto i = interests->begin();
  auto e = interests->end();

  while (i != e) {
    if (FD_ISSET(i->first, fdset)) {
      result->push_back(i->second);
      auto k = i;
      ++i;
      interests->erase(k);
    } else {
      i++;
    }
  }
}

size_t NativeScheduler::timerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return timers_.size();
}

size_t NativeScheduler::readerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return readers_.size();
}

size_t NativeScheduler::writerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return writers_.size();
}

void NativeScheduler::runLoopOnce() {
  fd_set input, output, error;
  FD_ZERO(&input);
  FD_ZERO(&output);
  FD_ZERO(&error);

  int wmark = 0;
  timeval tv;

  {
    std::lock_guard<std::mutex> lk(lock_);

    for (auto i: readers_) {
      FD_SET(i.first, &input);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    for (auto i: writers_) {
      FD_SET(i.first, &output);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    const TimeSpan nextTimeout = !tasks_.empty()
                               ? TimeSpan::Zero
                               : !timers_.empty()
                                 ? timers_.front().when - clock_->get()
                                 : TimeSpan::fromSeconds(4);

    tv.tv_sec = static_cast<time_t>(nextTimeout.totalSeconds()),
    tv.tv_usec = nextTimeout.microseconds();
  }

  FD_SET(wakeupPipe_[PIPE_READ_END], &input);

  int rv = ::select(wmark + 1, &input, &output, &error, &tv);
  if (rv < 0)
    throw SYSTEM_ERROR(errno);

  if (FD_ISSET(wakeupPipe_[PIPE_READ_END], &input)) {
    bool consumeMore = true;
    while (consumeMore) {
      char buf[sizeof(int) * 128];
      consumeMore = ::read(wakeupPipe_[PIPE_READ_END], buf, sizeof(buf)) > 0;
    }
  }

  collectTimeouts();

  std::vector<HandleRef> activeHandles;
  activeHandles.reserve(rv);

  std::deque<Task> activeTasks;
  {
    std::lock_guard<std::mutex> lk(lock_);

    collectActiveHandles(&readers_, &input, &activeHandles);
    collectActiveHandles(&writers_, &output, &activeHandles);
    activeTasks = std::move(tasks_);
  }

  safeCall(onPreInvokePending_);
  safeCallEach(activeHandles);
  safeCallEach(activeTasks);
  safeCall(onPostInvokePending_);
}

void NativeScheduler::breakLoop() {
  int dummy = 42;
  ::write(wakeupPipe_[PIPE_WRITE_END], &dummy, sizeof(dummy));
}

} // namespace xzero
<commit_msg>more cleanups<commit_after>#include <xzero/executor/NativeScheduler.h>
#include <xzero/RuntimeError.h>
#include <xzero/WallClock.h>
#include <xzero/sysconfig.h>
#include <algorithm>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>

namespace xzero {

#define PIPE_READ_END  0
#define PIPE_WRITE_END 1

/**
 * XXX
 * - registering a key should be *ONESHOT* and *Edge Triggered*
 * - remove SelectionKey::change()
 * - add SelectionKey::cancel()
 * - do we need Selectable then (just use EndPoinit or `int fd`?)
 *   - endpoint: operator int() { return handle(); }
 * - maybe inherit from Executor
 * - add a way to add timed callbacks that can be cancelled
 * - actual implementations inheriting from: Selector < Scheduler < Executor
 * - select: SelectEventLoop (currently: NativeScheduler)
 * - epoll: LinuxEventLoop
 *
 */

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock,
    std::function<void()> preInvoke,
    std::function<void()> postInvoke)
    : Scheduler(std::move(errorLogger)),
      clock_(clock ? clock : WallClock::system()),
      lock_(),
      wakeupPipe_(),
      onPreInvokePending_(preInvoke),
      onPostInvokePending_(postInvoke) {
  if (pipe(wakeupPipe_) < 0) {
    throw SYSTEM_ERROR(errno);
  }
  fcntl(wakeupPipe_[0], F_SETFL, O_NONBLOCK);
  fcntl(wakeupPipe_[1], F_SETFL, O_NONBLOCK);
}

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock)
    : NativeScheduler(errorLogger, clock, nullptr, nullptr) {
}

NativeScheduler::NativeScheduler()
    : NativeScheduler(nullptr, nullptr, nullptr, nullptr) {
}

NativeScheduler::~NativeScheduler() {
  ::close(wakeupPipe_[PIPE_READ_END]);
  ::close(wakeupPipe_[PIPE_WRITE_END]);
}

void NativeScheduler::execute(Task&& task) {
  {
    std::lock_guard<std::mutex> lk(lock_);
    tasks_.push_back(task);
  }
  breakLoop();
}

std::string NativeScheduler::toString() const {
  return "NativeScheduler";
}

Scheduler::HandleRef NativeScheduler::executeAfter(TimeSpan delay, Task task) {
  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  return insertIntoTimersList(clock_->get() + delay,
                              std::make_shared<Handle>(task, onCancel));
}

Scheduler::HandleRef NativeScheduler::executeAt(DateTime when, Task task) {
  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  //return insertIntoTimersList(when, std::make_shared<Handle>(task, onCancel));
  return insertIntoTimersList(when, std::make_shared<Handle>(task,
      std::bind(&NativeScheduler::removeFromTimersList, this, std::placeholders::_1)));
}

TimeSpan NativeScheduler::computeNextTimeout() {
  std::lock_guard<std::mutex> lk(lock_);

  return timers_.empty()
    ? timers_.front().when - clock_->get()
    : TimeSpan::fromSeconds(4);
}

Scheduler::HandleRef NativeScheduler::insertIntoTimersList(DateTime dt,
                                                           HandleRef handle) {
  Timer t = { dt, handle };

  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.end();
  auto e = timers_.begin();

  while (i != e) {
    i--;
    const Timer& current = *i;
    if (current.when >= t.when) {
      timers_.insert(i, t);
      return handle;
    }
  }

  if (i == e) {
    timers_.push_front(t);
  }

  return handle;
}

void NativeScheduler::removeFromTimersList(Handle* handle) {
  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.begin();
  auto e = timers_.end();

  while (i != e) {
    if (i->handle.get() == handle) {
      timers_.erase(i);
      break;
    }
    i++;
  }
}

void NativeScheduler::collectTimeouts() {
  const DateTime now = clock_->get();

  std::lock_guard<std::mutex> lk(lock_);

  for (;;) {
    if (timers_.empty())
      break;

    const Timer& job = timers_.front();

    if (job.when > now)
      break;

    tasks_.push_back(job.handle->getAction());
    timers_.pop_front();
  }
}

inline Scheduler::HandleRef registerInterest(
    std::mutex* registryLock,
    std::list<std::pair<int, Scheduler::HandleRef>>* registry,
    int fd,
    Executor::Task task) {

  auto onCancel = [=](Scheduler::Handle* h) {
    std::lock_guard<std::mutex> lk(*registryLock);
    for (auto i: *registry) {
      if (i.second.get() == h) {
        return registry->remove(i);
      }
    }
  };

  std::lock_guard<std::mutex> lk(*registryLock);
  auto handle = std::make_shared<Scheduler::Handle>(task, onCancel);
  registry->push_back(std::make_pair(fd, handle));

  return handle;
}

Scheduler::HandleRef NativeScheduler::executeOnReadable(int fd, Task task) {
  return registerInterest(&lock_, &readers_, fd, task);
}

Scheduler::HandleRef NativeScheduler::executeOnWritable(int fd, Task task) {
  return registerInterest(&lock_, &writers_, fd, task);
}

inline void collectActiveHandles(
    std::list<std::pair<int, Scheduler::HandleRef>>* interests,
    fd_set* fdset,
    std::vector<Scheduler::HandleRef>* result) {

  auto i = interests->begin();
  auto e = interests->end();

  while (i != e) {
    if (FD_ISSET(i->first, fdset)) {
      result->push_back(i->second);
      auto k = i;
      ++i;
      interests->erase(k);
    } else {
      i++;
    }
  }
}

size_t NativeScheduler::timerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return timers_.size();
}

size_t NativeScheduler::readerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return readers_.size();
}

size_t NativeScheduler::writerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return writers_.size();
}

void NativeScheduler::runLoopOnce() {
  fd_set input, output, error;
  FD_ZERO(&input);
  FD_ZERO(&output);
  FD_ZERO(&error);

  int wmark = 0;
  timeval tv;

  {
    std::lock_guard<std::mutex> lk(lock_);

    for (auto i: readers_) {
      FD_SET(i.first, &input);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    for (auto i: writers_) {
      FD_SET(i.first, &output);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    const TimeSpan nextTimeout = !tasks_.empty()
                               ? TimeSpan::Zero
                               : !timers_.empty()
                                 ? timers_.front().when - clock_->get()
                                 : TimeSpan::fromSeconds(4);

    tv.tv_sec = static_cast<time_t>(nextTimeout.totalSeconds()),
    tv.tv_usec = nextTimeout.microseconds();
  }

  FD_SET(wakeupPipe_[PIPE_READ_END], &input);

  int rv = ::select(wmark + 1, &input, &output, &error, &tv);
  if (rv < 0)
    throw SYSTEM_ERROR(errno);

  if (FD_ISSET(wakeupPipe_[PIPE_READ_END], &input)) {
    bool consumeMore = true;
    while (consumeMore) {
      char buf[sizeof(int) * 128];
      consumeMore = ::read(wakeupPipe_[PIPE_READ_END], buf, sizeof(buf)) > 0;
    }
  }

  collectTimeouts();

  std::vector<HandleRef> activeHandles;
  activeHandles.reserve(rv);

  std::deque<Task> activeTasks;
  {
    std::lock_guard<std::mutex> lk(lock_);

    collectActiveHandles(&readers_, &input, &activeHandles);
    collectActiveHandles(&writers_, &output, &activeHandles);
    activeTasks = std::move(tasks_);
  }

  safeCall(onPreInvokePending_);
  safeCallEach(activeHandles);
  safeCallEach(activeTasks);
  safeCall(onPostInvokePending_);
}

void NativeScheduler::breakLoop() {
  int dummy = 42;
  ::write(wakeupPipe_[PIPE_WRITE_END], &dummy, sizeof(dummy));
}

} // namespace xzero
<|endoftext|>


<commit_before>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Philip Deegan nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _KUL_PROC_HPP_
#define _KUL_PROC_HPP_

#include <string>
#include <tchar.h>
#include <stdio.h>
#include <sstream>
#include <strsafe.h>
#include <Windows.h>
#include <psapi.h>

#include "kul/os.hpp"
#include "kul/def.hpp"
#include "kul/log.hpp"
#include "kul/string.hpp"
#include "kul/proc.base.hpp"

// extern char **environ;
#include <iostream>

namespace kul{

namespace this_proc{
class MemGetter{
    private:
        PROCESS_MEMORY_COUNTERS_EX pmc;
        MemGetter(){
            GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
        }
        void virtula(uint64_t& v){
            v += pmc.PrivateUsage;
        }
        void physical(uint64_t& v){
            v += pmc.WorkingSetSize;
        }
        friend uint64_t virtualMemory();
        friend uint64_t physicalMemory();
        friend uint64_t totalMemory();
};
inline uint64_t virtualMemory(){
    uint64_t v = 0;
    MemGetter().virtula(v);
    return v;
}
inline uint64_t physicalMemory(){
    uint64_t v = 0;
    MemGetter().physical(v);
    return v;
}
inline uint64_t totalMemory(){
    uint64_t v = 0;
    MemGetter pg;
    pg.virtula(v);
    pg.physical(v);
    return v;
}

inline uint16_t cpuLoad(){
    return 0;
}

inline int32_t id(){
    return GetCurrentProcessId();
}
inline void kill(const int32_t& e){
    TerminateProcess(OpenProcess(PROCESS_TERMINATE, 0, kul::this_proc::id()), 128+e);
}
} // end namespace this_proc

class Process : public kul::AProcess{
    private:
        static ULONG PIPE_ID(){
            static ULONG p = 999;
            p++;
            return p;
        }
        HANDLE g_hChildStd_OUT_Rd = NULL;
        HANDLE g_hChildStd_OUT_Wr = NULL;
        HANDLE g_hChildStd_ERR_Rd = NULL;
        HANDLE g_hChildStd_ERR_Wr = NULL;

        HANDLE revent = CreateEvent(0, 1, 0, 0);
    public:
        Process(const std::string& cmd, const bool& wfe = true)                         : kul::AProcess(cmd, wfe)      {}
        Process(const std::string& cmd, const std::string& path, const bool& wfe = true): kul::AProcess(cmd, path, wfe){}
        Process(const std::string& cmd, const kul::Dir& d, const bool& wfe = true) : kul::AProcess(cmd, d ? d.real() : d.path(), wfe){}
        ~Process(){ tearDown(); }
        bool kill(int16_t k = 6){
            if(!started()) return 0;
            DWORD dwDesiredAccess = PROCESS_TERMINATE;
            bool  bInheritHandle  = 0;
            HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, pid());
            if (hProcess == NULL) return 0;
            bool r = TerminateProcess(hProcess, 128+k);
            CloseHandle(hProcess);
            setFinished();
            return r;
        }
        virtual void expand(std::string& s) const {
            std::string r = s;
            auto lb  = s.find("$(");
            auto clb = s.find("\\$(");
            while((lb - clb + 1) == 0){
                lb  = r.find("$(",   clb + 3);
                clb = r.find("\\$(", clb + 3);
            }
            if(lb == std::string::npos) return;
            auto rb  = s.find(")");
            auto crb = s.find("\\)");
            while((rb - crb + 1) == 0){
                rb  = r.find(")",   crb + 2);
                crb = r.find("\\)", crb + 2);
            }
            if(rb == std::string::npos) return;

            std::string k(r.substr(lb + 2, rb - 2 - lb));
            std::vector<std::string> cli(kul::cli::asArgs(k));
            std::stringstream ss;
            if(cli.size() > 1){
                kul::Process p(cli[0]);
                kul::ProcessCapture pc(p);
                for(size_t i = 1; i < cli.size(); i++) p.arg(cli[i]);
                p.start();
                std::string out(pc.outs());
                if(*out.rbegin() == '\n') out.pop_back();
                std::string t(r.substr(0, lb) + out + r.substr(rb + 1));
                ss << r.substr(0, lb) << out << r.substr(rb + 1);
            }else
                ss << r.substr(0, lb) << kul::env::GET(cli[0].c_str()) << r.substr(rb + 1);

            std::string t(ss.str());
            expand(t);
            s = t;
        }
    protected:
        void tearDown(){
            CloseHandle(g_hChildStd_OUT_Rd);
            CloseHandle(g_hChildStd_ERR_Rd);
        }
        void run() throw (kul::Exception){
            SECURITY_ATTRIBUTES sa;
            ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
            // Set the bInheritHandle flag so pipe handles are inherited.
            sa.nLength = sizeof(SECURITY_ATTRIBUTES);
            sa.bInheritHandle = TRUE;
            sa.lpSecurityDescriptor = NULL;

            std::stringstream ss;
            ss << this;

            const ULONG& pipeID = PIPE_ID();
            std::string pipeOut = "\\\\.\\Pipe\\kul_proc_out."+std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);
            std::string pipeErr = "\\\\.\\Pipe\\kul_proc_err."+std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);
            std::string pipeIn  = "\\\\.\\Pipe\\kul_proc_in." +std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);

            LPSTR lPipeOut = _strdup(pipeOut.c_str());
            g_hChildStd_OUT_Wr = ::CreateNamedPipeA(lPipeOut, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, __KUL_PROCESS_BUFFER__,
                 __KUL_PROCESS_BUFFER__, 0, &sa);
            if(!g_hChildStd_OUT_Wr) error(__LINE__, "CreatePipe failed");
            g_hChildStd_OUT_Rd = ::CreateFileA(lPipeOut, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
            if(!g_hChildStd_OUT_Rd) error(__LINE__, "CreatePipe failed");
            if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))  error(__LINE__, "SetHandleInformation failed");

            LPSTR lPipeErr = _strdup(pipeErr.c_str());
            g_hChildStd_ERR_Wr = ::CreateNamedPipeA(lPipeErr, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, __KUL_PROCESS_BUFFER__,
                 __KUL_PROCESS_BUFFER__, 0, &sa);
            if(!g_hChildStd_ERR_Wr) error(__LINE__, "CreatePipe failed");
            g_hChildStd_ERR_Rd = ::CreateFileA(lPipeErr, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
            if(!g_hChildStd_ERR_Rd) error(__LINE__, "CreatePipe failed");
            if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0))  error(__LINE__, "SetHandleInformation failed");

            bool bSuccess = FALSE;

            PROCESS_INFORMATION piProcInfo;
            STARTUPINFO siStartInfo;

            ZeroMemory(&piProcInfo,  sizeof(PROCESS_INFORMATION));
            ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

            siStartInfo.cb = sizeof(STARTUPINFO);
            siStartInfo.dwFlags = STARTF_USESTDHANDLES;
            siStartInfo.hStdError = g_hChildStd_ERR_Wr;
            siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
            siStartInfo.wShowWindow = SW_HIDE;
            siStartInfo.lpDesktop = NULL;
            siStartInfo.lpReserved = NULL;
            siStartInfo.lpTitle = NULL;
            siStartInfo.cbReserved2 = 0;
            siStartInfo.lpReserved2 = NULL;

            unsigned flags = CREATE_UNICODE_ENVIRONMENT;
            HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
                    FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL, NULL);
            if (cons == INVALID_HANDLE_VALUE) {
                flags |= DETACHED_PROCESS;
            } else {
                CloseHandle(cons);
            }

            preStart();

            LPTSTR lpszVariable;
            LPCH lpvEnv;
            lpvEnv = GetEnvironmentStrings();
            if (lpvEnv == NULL) error(__LINE__, "GetEnvironmentStrings() failed.");
            kul::hash::map::S2S env;
            for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++){
                std::stringstream ss;
                while (*lpszVariable) ss << *lpszVariable++;
                std::string var = ss.str();
                if(var.find(":") != std::string::npos)
                    env.insert(var.substr(0, var.find(":")), var.substr(var.find(":") + 1));
                else env.insert(var, "");
            }
            if(FreeEnvironmentStrings(lpvEnv) == 0) error(__LINE__, "FreeEnvironmentStrings() failed");

            const char* dir = directory().empty() ? 0 : directory().c_str();
            std::string cmd(toString());
            expand(cmd);
            LPSTR szCmdline = _strdup(cmd.c_str());
            if(vars().size()){
                WCHAR chNewEnv[__KUL_PROCESS_ENV_BUFFER__];
                LPWSTR lpszCurrentVariable;
                lpszCurrentVariable = (LPWSTR) chNewEnv;
                for(auto& evs : vars()){
                    std::string var(evs.first + "=" + evs.second);
                    if(FAILED(StringCchCopyW(lpszCurrentVariable, __KUL_PROCESS_ENV_BUFFER__, (std::wstring(var.begin(), var.end()).c_str()))))
                        error(__LINE__, "String copy failed");
                    lpszCurrentVariable += wcslen(lpszCurrentVariable) + 1;
                }
                for(auto& evs : env){
                    if(vars().count(evs.first)) continue;
                    std::string var(evs.first + "=" + evs.second);
                    if(FAILED(StringCchCopyW(lpszCurrentVariable, __KUL_PROCESS_ENV_BUFFER__, (std::wstring(var.begin(), var.end()).c_str()))))
                        error(__LINE__, "String copy failed");
                    lpszCurrentVariable += wcslen(lpszCurrentVariable) + 1;
                }
                *lpszCurrentVariable = (TCHAR)0;
                bSuccess = CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, flags, chNewEnv, dir, &siStartInfo, &piProcInfo);
            }else
                bSuccess = CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, flags, NULL,     dir, &siStartInfo, &piProcInfo);

            if(!bSuccess) error(__LINE__, "CreateProcess failed with last error: " + GetLastError());

            pid(piProcInfo.dwProcessId);

            CloseHandle(g_hChildStd_OUT_Wr);
            CloseHandle(g_hChildStd_ERR_Wr);

            if(this->waitForExit()){
                OVERLAPPED il = { 0 };
                memset(&il, 0, sizeof(il));
                il.hEvent = revent;
                OVERLAPPED ol = { 0 };
                memset(&ol, 0, sizeof(ol));
                ol.hEvent = revent;
                OVERLAPPED el = { 0 };
                memset(&el, 0, sizeof(el));
                el.hEvent = revent;

                DWORD dwRead;
                CHAR chBuf[__KUL_PROCESS_BUFFER__ + 1];
                bSuccess = FALSE;
                bool alive = true;
                do{
                    alive = WaitForSingleObject(piProcInfo.hProcess, 11) == WAIT_TIMEOUT;
                    for (;;) {
                        dwRead = 0;
                        bSuccess = ::ReadFile( g_hChildStd_OUT_Rd, chBuf, __KUL_PROCESS_BUFFER__, &dwRead, &ol);
                        while(!bSuccess && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE)){
                            WaitForSingleObject(ol.hEvent, 11);
                            bSuccess = GetOverlappedResult(g_hChildStd_OUT_Rd, &ol, &dwRead, 0);
                        }
                        if(!bSuccess || dwRead == 0) break;
                        chBuf[dwRead] = '\0';
                        out(std::string(chBuf, dwRead));
                    }
                    for (;;) {
                        dwRead = 0;
                        bSuccess = ::ReadFile( g_hChildStd_ERR_Rd, chBuf, __KUL_PROCESS_BUFFER__, &dwRead, &el);
                        if (GetLastError() == ERROR_IO_PENDING) {
                            WaitForSingleObject(el.hEvent, 11);
                            bSuccess = GetOverlappedResult(g_hChildStd_OUT_Rd, &el, &dwRead, 0);
                        }
                        if(!bSuccess || dwRead == 0) break;
                        chBuf[dwRead] = '\0';
                        err(std::string(chBuf, dwRead));
                    }
                }while(alive);
            }
            tearDown();
            if(this->waitForExit()){
                DWORD ec = 0;
                if (FALSE == GetExitCodeProcess(piProcInfo.hProcess, &ec))
                    KEXCEPT(kul::proc::Exception, "GetExitCodeProcess failure");
                exitCode(ec);
                finish();
                setFinished();
            }
            CloseHandle(piProcInfo.hThread);
            CloseHandle(piProcInfo.hProcess);
        }
    };
}

#endif /* _KUL_PROC_HPP_ */
<commit_msg>Update proc.hpp<commit_after>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Philip Deegan nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _KUL_PROC_HPP_
#define _KUL_PROC_HPP_

#include <string>
#include <tchar.h>
#include <stdio.h>
#include <sstream>
#include <strsafe.h>
#include <Windows.h>
#include <psapi.h>

#include "kul/os.hpp"
#include "kul/def.hpp"
#include "kul/log.hpp"
#include "kul/string.hpp"
#include "kul/proc.base.hpp"

// extern char **environ;

namespace kul{

namespace this_proc{
class MemGetter{
    private:
        PROCESS_MEMORY_COUNTERS_EX pmc;
        MemGetter(){
            GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
        }
        void virtula(uint64_t& v){
            v += pmc.PrivateUsage;
        }
        void physical(uint64_t& v){
            v += pmc.WorkingSetSize;
        }
        friend uint64_t virtualMemory();
        friend uint64_t physicalMemory();
        friend uint64_t totalMemory();
};
inline uint64_t virtualMemory(){
    uint64_t v = 0;
    MemGetter().virtula(v);
    return v;
}
inline uint64_t physicalMemory(){
    uint64_t v = 0;
    MemGetter().physical(v);
    return v;
}
inline uint64_t totalMemory(){
    uint64_t v = 0;
    MemGetter pg;
    pg.virtula(v);
    pg.physical(v);
    return v;
}

inline uint16_t cpuLoad(){
    return 0;
}

inline int32_t id(){
    return GetCurrentProcessId();
}
inline void kill(const int32_t& e){
    TerminateProcess(OpenProcess(PROCESS_TERMINATE, 0, kul::this_proc::id()), 128+e);
}
} // end namespace this_proc

class Process : public kul::AProcess{
    private:
        static ULONG PIPE_ID(){
            static ULONG p = 999;
            p++;
            return p;
        }
        HANDLE g_hChildStd_OUT_Rd = NULL;
        HANDLE g_hChildStd_OUT_Wr = NULL;
        HANDLE g_hChildStd_ERR_Rd = NULL;
        HANDLE g_hChildStd_ERR_Wr = NULL;

        HANDLE revent = CreateEvent(0, 1, 0, 0);
    public:
        Process(const std::string& cmd, const bool& wfe = true)                         : kul::AProcess(cmd, wfe)      {}
        Process(const std::string& cmd, const std::string& path, const bool& wfe = true): kul::AProcess(cmd, path, wfe){}
        Process(const std::string& cmd, const kul::Dir& d, const bool& wfe = true) : kul::AProcess(cmd, d ? d.real() : d.path(), wfe){}
        ~Process(){ tearDown(); }
        bool kill(int16_t k = 6){
            if(!started()) return 0;
            DWORD dwDesiredAccess = PROCESS_TERMINATE;
            bool  bInheritHandle  = 0;
            HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, pid());
            if (hProcess == NULL) return 0;
            bool r = TerminateProcess(hProcess, 128+k);
            CloseHandle(hProcess);
            setFinished();
            return r;
        }
        virtual void expand(std::string& s) const {
            std::string r = s;
            auto lb  = s.find("$(");
            auto clb = s.find("\\$(");
            while((lb - clb + 1) == 0){
                lb  = r.find("$(",   clb + 3);
                clb = r.find("\\$(", clb + 3);
            }
            if(lb == std::string::npos) return;
            auto rb  = s.find(")");
            auto crb = s.find("\\)");
            while((rb - crb + 1) == 0){
                rb  = r.find(")",   crb + 2);
                crb = r.find("\\)", crb + 2);
            }
            if(rb == std::string::npos) return;

            std::string k(r.substr(lb + 2, rb - 2 - lb));
            std::vector<std::string> cli(kul::cli::asArgs(k));
            std::stringstream ss;
            if(cli.size() > 1){
                kul::Process p(cli[0]);
                kul::ProcessCapture pc(p);
                for(size_t i = 1; i < cli.size(); i++) p.arg(cli[i]);
                p.start();
                std::string out(pc.outs());
                if(*out.rbegin() == '\n') out.pop_back();
                std::string t(r.substr(0, lb) + out + r.substr(rb + 1));
                ss << r.substr(0, lb) << out << r.substr(rb + 1);
            }else
                ss << r.substr(0, lb) << kul::env::GET(cli[0].c_str()) << r.substr(rb + 1);

            std::string t(ss.str());
            expand(t);
            s = t;
        }
    protected:
        void tearDown(){
            CloseHandle(g_hChildStd_OUT_Rd);
            CloseHandle(g_hChildStd_ERR_Rd);
        }
        void run() throw (kul::Exception){
            SECURITY_ATTRIBUTES sa;
            ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
            // Set the bInheritHandle flag so pipe handles are inherited.
            sa.nLength = sizeof(SECURITY_ATTRIBUTES);
            sa.bInheritHandle = TRUE;
            sa.lpSecurityDescriptor = NULL;

            std::stringstream ss;
            ss << this;

            const ULONG& pipeID = PIPE_ID();
            std::string pipeOut = "\\\\.\\Pipe\\kul_proc_out."+std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);
            std::string pipeErr = "\\\\.\\Pipe\\kul_proc_err."+std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);
            std::string pipeIn  = "\\\\.\\Pipe\\kul_proc_in." +std::to_string(this_proc::id())+"."+ss.str()+"."+std::to_string(pipeID);

            LPSTR lPipeOut = _strdup(pipeOut.c_str());
            g_hChildStd_OUT_Wr = ::CreateNamedPipeA(lPipeOut, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, __KUL_PROCESS_BUFFER__,
                 __KUL_PROCESS_BUFFER__, 0, &sa);
            if(!g_hChildStd_OUT_Wr) error(__LINE__, "CreatePipe failed");
            g_hChildStd_OUT_Rd = ::CreateFileA(lPipeOut, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
            if(!g_hChildStd_OUT_Rd) error(__LINE__, "CreatePipe failed");
            if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))  error(__LINE__, "SetHandleInformation failed");

            LPSTR lPipeErr = _strdup(pipeErr.c_str());
            g_hChildStd_ERR_Wr = ::CreateNamedPipeA(lPipeErr, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, __KUL_PROCESS_BUFFER__,
                 __KUL_PROCESS_BUFFER__, 0, &sa);
            if(!g_hChildStd_ERR_Wr) error(__LINE__, "CreatePipe failed");
            g_hChildStd_ERR_Rd = ::CreateFileA(lPipeErr, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
            if(!g_hChildStd_ERR_Rd) error(__LINE__, "CreatePipe failed");
            if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0))  error(__LINE__, "SetHandleInformation failed");

            bool bSuccess = FALSE;

            PROCESS_INFORMATION piProcInfo;
            STARTUPINFO siStartInfo;

            ZeroMemory(&piProcInfo,  sizeof(PROCESS_INFORMATION));
            ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));

            siStartInfo.cb = sizeof(STARTUPINFO);
            siStartInfo.dwFlags = STARTF_USESTDHANDLES;
            siStartInfo.hStdError = g_hChildStd_ERR_Wr;
            siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
            siStartInfo.wShowWindow = SW_HIDE;
            siStartInfo.lpDesktop = NULL;
            siStartInfo.lpReserved = NULL;
            siStartInfo.lpTitle = NULL;
            siStartInfo.cbReserved2 = 0;
            siStartInfo.lpReserved2 = NULL;

            unsigned flags = CREATE_UNICODE_ENVIRONMENT;
            HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
                    FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL, NULL);
            if (cons == INVALID_HANDLE_VALUE) {
                flags |= DETACHED_PROCESS;
            } else {
                CloseHandle(cons);
            }

            preStart();

            LPTSTR lpszVariable;
            LPCH lpvEnv;
            lpvEnv = GetEnvironmentStrings();
            if (lpvEnv == NULL) error(__LINE__, "GetEnvironmentStrings() failed.");
            kul::hash::map::S2S env;
            for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++){
                std::stringstream ss;
                while (*lpszVariable) ss << *lpszVariable++;
                std::string var = ss.str();
                if(var.find(":") != std::string::npos)
                    env.insert(var.substr(0, var.find(":")), var.substr(var.find(":") + 1));
                else env.insert(var, "");
            }
            if(FreeEnvironmentStrings(lpvEnv) == 0) error(__LINE__, "FreeEnvironmentStrings() failed");

            const char* dir = directory().empty() ? 0 : directory().c_str();
            std::string cmd(toString());
            expand(cmd);
            LPSTR szCmdline = _strdup(cmd.c_str());
            if(vars().size()){
                WCHAR chNewEnv[__KUL_PROCESS_ENV_BUFFER__];
                LPWSTR lpszCurrentVariable;
                lpszCurrentVariable = (LPWSTR) chNewEnv;
                for(auto& evs : vars()){
                    std::string var(evs.first + "=" + evs.second);
                    if(FAILED(StringCchCopyW(lpszCurrentVariable, __KUL_PROCESS_ENV_BUFFER__, (std::wstring(var.begin(), var.end()).c_str()))))
                        error(__LINE__, "String copy failed");
                    lpszCurrentVariable += wcslen(lpszCurrentVariable) + 1;
                }
                for(auto& evs : env){
                    if(vars().count(evs.first)) continue;
                    std::string var(evs.first + "=" + evs.second);
                    if(FAILED(StringCchCopyW(lpszCurrentVariable, __KUL_PROCESS_ENV_BUFFER__, (std::wstring(var.begin(), var.end()).c_str()))))
                        error(__LINE__, "String copy failed");
                    lpszCurrentVariable += wcslen(lpszCurrentVariable) + 1;
                }
                *lpszCurrentVariable = (TCHAR)0;
                bSuccess = CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, flags, chNewEnv, dir, &siStartInfo, &piProcInfo);
            }else
                bSuccess = CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, flags, NULL,     dir, &siStartInfo, &piProcInfo);

            if(!bSuccess) error(__LINE__, "CreateProcess failed with last error: " + GetLastError());

            pid(piProcInfo.dwProcessId);

            CloseHandle(g_hChildStd_OUT_Wr);
            CloseHandle(g_hChildStd_ERR_Wr);

            if(this->waitForExit()){
                OVERLAPPED il = { 0 };
                memset(&il, 0, sizeof(il));
                il.hEvent = revent;
                OVERLAPPED ol = { 0 };
                memset(&ol, 0, sizeof(ol));
                ol.hEvent = revent;
                OVERLAPPED el = { 0 };
                memset(&el, 0, sizeof(el));
                el.hEvent = revent;

                DWORD dwRead;
                CHAR chBuf[__KUL_PROCESS_BUFFER__ + 1];
                bSuccess = FALSE;
                bool alive = true;
                do{
                    alive = WaitForSingleObject(piProcInfo.hProcess, 11) == WAIT_TIMEOUT;
                    for (;;) {
                        dwRead = 0;
                        bSuccess = ::ReadFile( g_hChildStd_OUT_Rd, chBuf, __KUL_PROCESS_BUFFER__, &dwRead, &ol);
                        while(!bSuccess && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE)){
                            WaitForSingleObject(ol.hEvent, 11);
                            bSuccess = GetOverlappedResult(g_hChildStd_OUT_Rd, &ol, &dwRead, 0);
                        }
                        if(!bSuccess || dwRead == 0) break;
                        chBuf[dwRead] = '\0';
                        out(std::string(chBuf, dwRead));
                    }
                    for (;;) {
                        dwRead = 0;
                        bSuccess = ::ReadFile( g_hChildStd_ERR_Rd, chBuf, __KUL_PROCESS_BUFFER__, &dwRead, &el);
                        if (GetLastError() == ERROR_IO_PENDING) {
                            WaitForSingleObject(el.hEvent, 11);
                            bSuccess = GetOverlappedResult(g_hChildStd_OUT_Rd, &el, &dwRead, 0);
                        }
                        if(!bSuccess || dwRead == 0) break;
                        chBuf[dwRead] = '\0';
                        err(std::string(chBuf, dwRead));
                    }
                }while(alive);
            }
            tearDown();
            if(this->waitForExit()){
                DWORD ec = 0;
                if (FALSE == GetExitCodeProcess(piProcInfo.hProcess, &ec))
                    KEXCEPT(kul::proc::Exception, "GetExitCodeProcess failure");
                exitCode(ec);
                finish();
                setFinished();
            }
            CloseHandle(piProcInfo.hThread);
            CloseHandle(piProcInfo.hProcess);
        }
    };
}

#endif /* _KUL_PROC_HPP_ */
<|endoftext|>


<commit_before>/*
    This file is part of libkdepim.

    Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qapplication.h>
#include <qevent.h>
#include <qlineedit.h>
#include <qpixmap.h>
#include <qpushbutton.h>

#include <kdatepicker.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knotifyclient.h>

#include "kdateedit.h"
#include "kdateedit.moc"

KDateEdit::KDateEdit(QWidget *parent, const char *name)
  : QHBox(parent, name)
{
  mDateEdit = new QLineEdit(this);
  mDateEdit->setText(KGlobal::locale()->formatDate(QDate::currentDate(),true));
  setFocusProxy(mDateEdit);
  mDateEdit->installEventFilter(this);

  QPixmap pixmap = SmallIcon("smallcal");
  mDateButton = new QPushButton(this);
  mDateButton->setPixmap(pixmap);

  mDateFrame = new QVBox(0,0,WType_Popup);
  mDateFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
  mDateFrame->setFixedSize(200,200);
  mDateFrame->setLineWidth(3);
  mDateFrame->hide();

  mDatePicker = new KDatePicker(mDateFrame,QDate::currentDate());

  connect(mDateEdit,SIGNAL(returnPressed()),SLOT(lineEnterPressed()));
  connect(mDateEdit,SIGNAL(textChanged(const QString &)),
          SLOT(textChanged(const QString &)));

  connect(mDateButton,SIGNAL(clicked()),SLOT(toggleDatePicker()));

  connect(mDatePicker,SIGNAL(dateSelected(QDate)),SLOT(setDate(QDate)));
  connect(mDatePicker,SIGNAL(dateSelected(QDate)),SIGNAL(dateChanged(QDate)));
  connect(mDatePicker,SIGNAL(dateSelected(QDate)),mDateFrame,SLOT(hide()));

  // Create the keyword list. This will be used to match against when the user
  // enters information.
  mKeywordMap[i18n("tomorrow")] = 1;
  mKeywordMap[i18n("today")] = 0;
  mKeywordMap[i18n("yesterday")] = -1;

  /*
   * This loop uses some math tricks to figure out the offset in days
   * to the next date the given day of the week occurs. There
   * are two cases, that the new day is >= the current day, which means
   * the new day has not occured yet or that the new day < the current day,
   * which means the new day is already passed (so we need to find the
   * day in the next week).
   */
  QString dayName;
  int currentDay = QDate::currentDate().dayOfWeek();
  for (int i = 1; i <= 7; ++i)
  {
    dayName = KGlobal::locale()->weekDayName(i).lower();
    if (i >= currentDay)
      mKeywordMap[dayName] = i - currentDay;
    else
      mKeywordMap[dayName] = 7 - currentDay + i;
  }

  mTextChanged = false;
  mHandleInvalid = false;
}

KDateEdit::~KDateEdit()
{
  delete mDateFrame;
}

void KDateEdit::setDate(QDate newDate)
{
  if (!newDate.isValid() && !mHandleInvalid)
    return;

  QString dateString = "";
  if(newDate.isValid())
    dateString = KGlobal::locale()->formatDate( newDate, true );

  mTextChanged = false;

  // We do not want to generate a signal here, since we explicity setting
  // the date
  bool b = mDateEdit->signalsBlocked();
  mDateEdit->blockSignals(true);
  mDateEdit->setText(dateString);
  mDateEdit->blockSignals(b);
}

void KDateEdit::setHandleInvalid(bool handleInvalid)
{
  mHandleInvalid = handleInvalid;
}

void KDateEdit::setEnabled(bool on)
{
  mDateEdit->setEnabled(on);
  mDateButton->setEnabled(on);
}

QDate KDateEdit::date() const
{
  QDate date = readDate();

  if (date.isValid() || mHandleInvalid) {
    return date;
  } else {
    KNotifyClient::beep();
    return QDate::currentDate();
  }
}

void KDateEdit::toggleDatePicker()
{
  if( mDateFrame->isVisible() ) {
    mDateFrame->hide();
  } else {
    QPoint tmpPoint = mapToGlobal(mDateButton->geometry().bottomRight());

    if ( tmpPoint.x() < 207 ) tmpPoint.setX( 207 );

    int h = QApplication::desktop()->height();

    if ( tmpPoint.y() + 200 > h ) tmpPoint.setY( h - 200 );

    mDateFrame->setGeometry(tmpPoint.x()-207, tmpPoint.y(), 200, 200);

    QDate date = readDate();
    if(date.isValid()) {
      mDatePicker->setDate(date);
    } else {
      mDatePicker->setDate(QDate::currentDate());
    }
    mDateFrame->show();
  }
}

void KDateEdit::lineEnterPressed()
{
  QDate date = readDate();

  if(date.isValid())
  {
    // Update the edit. This is needed if the user has entered a
    // word rather than the actual date.
    setDate(date);

    emit(dateChanged(date));
  }
  else
  {
    if ( !mDateEdit->text().isEmpty() ) {
      mTextChanged = false;
      QString text = i18n( "You entered an invalid date! Will use current date instead." );
      if ( KMessageBox::warningContinueCancel( 0, text ) == KMessageBox::Continue ) {
          setDate( QDate::currentDate() );
          emit dateChanged( QDate::currentDate() );
      }
    }
  }
}

bool KDateEdit::inputIsValid()
{
  return readDate().isValid();
}

QDate KDateEdit::readDate() const
{
  QString text = mDateEdit->text();
  QDate date;

  if (mKeywordMap.contains(text.lower()))
  {
    date = QDate::currentDate().addDays(mKeywordMap[text.lower()]);
  }
  else
  {
    date = KGlobal::locale()->readDate(text);
  }

  return date;
}

bool KDateEdit::eventFilter(QObject *, QEvent *e)
{
  // We only process the focus out event if the text has changed
  // since we got focus
  if ((e->type() == QEvent::FocusOut) && mTextChanged)
  {
    lineEnterPressed();
    mTextChanged = false;
  }

  return false;
}

void KDateEdit::textChanged(const QString &)
{
  if(mHandleInvalid && mDateEdit->text().stripWhiteSpace().isEmpty()) {
    QDate date; //invalid date
    emit(dateChanged(date));
  } else  {
    mTextChanged = true;
  }
}
<commit_msg>Hard-coded sizes are never a good idea, use SizeHint.<commit_after>/*
    This file is part of libkdepim.

    Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qapplication.h>
#include <qevent.h>
#include <qlineedit.h>
#include <qpixmap.h>
#include <qpushbutton.h>

#include <kdatepicker.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knotifyclient.h>

#include "kdateedit.h"
#include "kdateedit.moc"

KDateEdit::KDateEdit(QWidget *parent, const char *name)
  : QHBox(parent, name)
{
  mDateEdit = new QLineEdit(this);
  mDateEdit->setText(KGlobal::locale()->formatDate(QDate::currentDate(),true));
  setFocusProxy(mDateEdit);
  mDateEdit->installEventFilter(this);

  QPixmap pixmap = SmallIcon("smallcal");
  mDateButton = new QPushButton(this);
  mDateButton->setPixmap(pixmap);

  mDateFrame = new QVBox(0,0,WType_Popup);
  mDateFrame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
  mDateFrame->setLineWidth(3);
  mDateFrame->hide();

  mDatePicker = new KDatePicker(mDateFrame,QDate::currentDate());

  connect(mDateEdit,SIGNAL(returnPressed()),SLOT(lineEnterPressed()));
  connect(mDateEdit,SIGNAL(textChanged(const QString &)),
          SLOT(textChanged(const QString &)));

  connect(mDateButton,SIGNAL(clicked()),SLOT(toggleDatePicker()));

  connect(mDatePicker,SIGNAL(dateSelected(QDate)),SLOT(setDate(QDate)));
  connect(mDatePicker,SIGNAL(dateSelected(QDate)),SIGNAL(dateChanged(QDate)));
  connect(mDatePicker,SIGNAL(dateSelected(QDate)),mDateFrame,SLOT(hide()));

  // Create the keyword list. This will be used to match against when the user
  // enters information.
  mKeywordMap[i18n("tomorrow")] = 1;
  mKeywordMap[i18n("today")] = 0;
  mKeywordMap[i18n("yesterday")] = -1;

  /*
   * This loop uses some math tricks to figure out the offset in days
   * to the next date the given day of the week occurs. There
   * are two cases, that the new day is >= the current day, which means
   * the new day has not occured yet or that the new day < the current day,
   * which means the new day is already passed (so we need to find the
   * day in the next week).
   */
  QString dayName;
  int currentDay = QDate::currentDate().dayOfWeek();
  for (int i = 1; i <= 7; ++i)
  {
    dayName = KGlobal::locale()->weekDayName(i).lower();
    if (i >= currentDay)
      mKeywordMap[dayName] = i - currentDay;
    else
      mKeywordMap[dayName] = 7 - currentDay + i;
  }

  mTextChanged = false;
  mHandleInvalid = false;
}

KDateEdit::~KDateEdit()
{
  delete mDateFrame;
}

void KDateEdit::setDate(QDate newDate)
{
  if (!newDate.isValid() && !mHandleInvalid)
    return;

  QString dateString = "";
  if(newDate.isValid())
    dateString = KGlobal::locale()->formatDate( newDate, true );

  mTextChanged = false;

  // We do not want to generate a signal here, since we explicity setting
  // the date
  bool b = mDateEdit->signalsBlocked();
  mDateEdit->blockSignals(true);
  mDateEdit->setText(dateString);
  mDateEdit->blockSignals(b);
}

void KDateEdit::setHandleInvalid(bool handleInvalid)
{
  mHandleInvalid = handleInvalid;
}

void KDateEdit::setEnabled(bool on)
{
  mDateEdit->setEnabled(on);
  mDateButton->setEnabled(on);
}

QDate KDateEdit::date() const
{
  QDate date = readDate();

  if (date.isValid() || mHandleInvalid) {
    return date;
  } else {
    KNotifyClient::beep();
    return QDate::currentDate();
  }
}

void KDateEdit::toggleDatePicker()
{
  if( mDateFrame->isVisible() ) {
    mDateFrame->hide();
  } else {
    QPoint tmpPoint = mapToGlobal(mDateButton->geometry().bottomRight());
    QSize datepickersize = mDatePicker->sizeHint();

    if ( tmpPoint.x() < 7+datepickersize.width() ) tmpPoint.setX( 7+datepickersize.width() );

    int h = QApplication::desktop()->height();

    if ( tmpPoint.y() + datepickersize.height() > h ) tmpPoint.setY( h - datepickersize.height() );

    mDateFrame->setGeometry(tmpPoint.x()-datepickersize.width()-7, tmpPoint.y(),
     datepickersize.width()+2*mDateFrame->lineWidth(), datepickersize.height()+2*mDateFrame->lineWidth());

    QDate date = readDate();
    if(date.isValid()) {
      mDatePicker->setDate(date);
    } else {
      mDatePicker->setDate(QDate::currentDate());
    }
    mDateFrame->show();
  }
}

void KDateEdit::lineEnterPressed()
{
  QDate date = readDate();

  if(date.isValid())
  {
    // Update the edit. This is needed if the user has entered a
    // word rather than the actual date.
    setDate(date);

    emit(dateChanged(date));
  }
  else
  {
    if ( !mDateEdit->text().isEmpty() ) {
      mTextChanged = false;
      QString text = i18n( "You entered an invalid date! Will use current date instead." );
      if ( KMessageBox::warningContinueCancel( 0, text ) == KMessageBox::Continue ) {
          setDate( QDate::currentDate() );
          emit dateChanged( QDate::currentDate() );
      }
    }
  }
}

bool KDateEdit::inputIsValid()
{
  return readDate().isValid();
}

QDate KDateEdit::readDate() const
{
  QString text = mDateEdit->text();
  QDate date;

  if (mKeywordMap.contains(text.lower()))
  {
    date = QDate::currentDate().addDays(mKeywordMap[text.lower()]);
  }
  else
  {
    date = KGlobal::locale()->readDate(text);
  }

  return date;
}

bool KDateEdit::eventFilter(QObject *, QEvent *e)
{
  // We only process the focus out event if the text has changed
  // since we got focus
  if ((e->type() == QEvent::FocusOut) && mTextChanged)
  {
    lineEnterPressed();
    mTextChanged = false;
  }

  return false;
}

void KDateEdit::textChanged(const QString &)
{
  if(mHandleInvalid && mDateEdit->text().stripWhiteSpace().isEmpty()) {
    QDate date; //invalid date
    emit(dateChanged(date));
  } else  {
    mTextChanged = true;
  }
}
<|endoftext|>


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

#include "memrev.h"

#include <cstddef>
#include <cstring>
#include <cstdlib>
#include <stdint.h>

#define UNREACHABLE() __builtin_unreachable()

using namespace std;

namespace {

/// Reverses the order of the first \a count units of \a data using a simple
/// swap algorithm.
template<typename T>
void Reverse(T* data, size_t count) {
    T* data_end = data + count;
    for (size_t i = 0; i < count / 2; i++) {
        T e = data[i];
        data[i] = data_end[-1 - i];
        data_end[-1 - i] = e;
    }
}

/// Returns a pointer whose integer value is the largest multiple of
/// alignof(T) less than or equal to \a ptr.
template<typename T>
inline T* AlignBack(const void* ptr) {
    const size_t alignment = alignof(T);
    return (T*) (((uintptr_t) ptr / alignment) * alignment);
}

/// Returns a pointer whose integer value is the smallest multiple of
/// alignof(T) greater than or equal to \a ptr.
template<typename T>
inline T* AlignFront(const void* ptr) {
    const size_t alignment = alignof(T);
    return (T*) ((((uintptr_t) ptr + alignment - 1) / alignment) * alignment);
}

#ifdef USE_VECTOR
#include "__vector.h"

/// Returns a copy of \a vec with the units reversed.
template<typename Unit, typename Vector>
inline Vector ReverseVector(const Vector& vec) {
    switch (sizeof(Unit)) {
    case 1:
        return ReverseVector8(vec);
    case 2:
        return ReverseVector16(vec);
    case 4:
        return ReverseVector32(vec);
    case 8:
        return ReverseVector64(vec);
    }
    UNREACHABLE();
}

/// The intermediate stage of the vector reversal algorithm.
/// (See MemrevImpl)
void ShiftMiddleAndSwapSides(char* data, size_t data_length,
                             size_t start_length, size_t end_length) {
    char* data_end = data + data_length;
    char* sides_temp;
    size_t sides_length = start_length + end_length;
    // Save the sides.
    if (sides_length > 0) {
        sides_temp = new char[sides_length];
        memcpy(sides_temp, data, start_length);
        memcpy(sides_temp + start_length, data_end - end_length, end_length);
    }

    // Shift the middle.
    if (start_length != end_length) {
        memmove(data + end_length, data + start_length,
                data_length - sides_length);
    }

    // Restore the sides, swapped.
    if (sides_length > 0) {
        memcpy(data, sides_temp + start_length, end_length);
        memcpy(data_end - start_length, sides_temp, start_length);
        delete [] sides_temp;
    }
}

template<typename Vector, typename T>
void MemrevImpl(T* data, size_t count) {
    // First, we need to find a subset of the array with SIMD-aligned bounds
    // and a length that is a multiple of twice the SIMD register width.
    Vector* vector_start = AlignFront<Vector>(data);
    Vector* vector_end = AlignBack<Vector>(&data[count]);
    ptrdiff_t total_vectors = vector_end - vector_start;
    if (total_vectors % 2) {
        total_vectors--;
        vector_end--;
    }

    // Only use vector acceleration if
    //  (1) we have a large enough array for it to make a difference, and
    //  (2) the vector region is aligned with |data|
    const ptrdiff_t kMinVectors = 2;
    size_t vector_offset = (uintptr_t) vector_start - (uintptr_t) data;
    if (total_vectors < kMinVectors || vector_offset % sizeof(T) != 0) {
        Reverse(data, count);
        return;
    }

    // We've found a suitable subset. Do the actual swapping.
    for (size_t i = 0; i < total_vectors / 2; i++) {
        Vector v = ReverseVector<T>(vector_start[i]);
        vector_start[i] = ReverseVector<T>(vector_end[-1 - i]);
        vector_end[-1 - i] = v;
    }

    // Our subset of the array is now reversed. But:
    //  (a) There may be unreversed bytes at the beginning and/or end.
    //  (b) The reversed subset may need shifting to its final position.
    size_t vector_end_offset = (uintptr_t) &data[count] -
                                (uintptr_t) vector_end;
    ShiftMiddleAndSwapSides((char*) data, count * sizeof(T),
                            vector_offset, vector_end_offset);

    // Reverse the remaining start and end units. Note that after
    // ShiftMiddleAndSwapSides(), |vector_offset| is the number of unreversed
    // bytes at the *end* of the array.
    Reverse(data, vector_end_offset / sizeof(T));
    size_t remaining_end_units = vector_offset / sizeof(T);
    Reverse(&data[count - remaining_end_units], remaining_end_units);
}

#define CALL_MEMREV_IMPL(WIDTH) \
    MemrevImpl<Vector ## WIDTH>((uint ## WIDTH ##_t*) data, count)

#else // USE_VECTOR

template<typename T>
void MemrevImpl(T* data, size_t count) {
    Reverse(data, count);
}

#define CALL_MEMREV_IMPL(WIDTH) \
    MemrevImpl((uint ## WIDTH ##_t*) data, count)

#endif // USE_VECTOR

} // namespace

void* memrev_reverse(void* data, size_t size, size_t count) {
    const static size_t kMaxUnitSize = 8;
    if (size == 0 || size > kMaxUnitSize || size & (size - 1))
        return NULL;

    switch (size) {
    case 1:
        CALL_MEMREV_IMPL(8);
        break;
    case 2:
        CALL_MEMREV_IMPL(16);
        break;
    case 4:
        CALL_MEMREV_IMPL(32);
        break;
    case 8:
        CALL_MEMREV_IMPL(64);
        break;
    }
    return data;
}
<commit_msg>[libmemrev] Get rid of superfluous checks in memrev_reverse().<commit_after>// Copyright 2012 Philip Puryear
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "memrev.h"

#include <cstddef>
#include <cstring>
#include <cstdlib>
#include <stdint.h>

#define UNREACHABLE() __builtin_unreachable()

using namespace std;

namespace {

/// Reverses the order of the first \a count units of \a data using a simple
/// swap algorithm.
template<typename T>
void Reverse(T* data, size_t count) {
    T* data_end = data + count;
    for (size_t i = 0; i < count / 2; i++) {
        T e = data[i];
        data[i] = data_end[-1 - i];
        data_end[-1 - i] = e;
    }
}

/// Returns a pointer whose integer value is the largest multiple of
/// alignof(T) less than or equal to \a ptr.
template<typename T>
inline T* AlignBack(const void* ptr) {
    const size_t alignment = alignof(T);
    return (T*) (((uintptr_t) ptr / alignment) * alignment);
}

/// Returns a pointer whose integer value is the smallest multiple of
/// alignof(T) greater than or equal to \a ptr.
template<typename T>
inline T* AlignFront(const void* ptr) {
    const size_t alignment = alignof(T);
    return (T*) ((((uintptr_t) ptr + alignment - 1) / alignment) * alignment);
}

#ifdef USE_VECTOR
#include "__vector.h"

/// Returns a copy of \a vec with the units reversed.
template<typename Unit, typename Vector>
inline Vector ReverseVector(const Vector& vec) {
    switch (sizeof(Unit)) {
    case 1:
        return ReverseVector8(vec);
    case 2:
        return ReverseVector16(vec);
    case 4:
        return ReverseVector32(vec);
    case 8:
        return ReverseVector64(vec);
    }
    UNREACHABLE();
}

/// The intermediate stage of the vector reversal algorithm.
/// (See MemrevImpl)
void ShiftMiddleAndSwapSides(char* data, size_t data_length,
                             size_t start_length, size_t end_length) {
    char* data_end = data + data_length;
    char* sides_temp;
    size_t sides_length = start_length + end_length;
    // Save the sides.
    if (sides_length > 0) {
        sides_temp = new char[sides_length];
        memcpy(sides_temp, data, start_length);
        memcpy(sides_temp + start_length, data_end - end_length, end_length);
    }

    // Shift the middle.
    if (start_length != end_length) {
        memmove(data + end_length, data + start_length,
                data_length - sides_length);
    }

    // Restore the sides, swapped.
    if (sides_length > 0) {
        memcpy(data, sides_temp + start_length, end_length);
        memcpy(data_end - start_length, sides_temp, start_length);
        delete [] sides_temp;
    }
}

template<typename Vector, typename T>
void MemrevImpl(T* data, size_t count) {
    // First, we need to find a subset of the array with SIMD-aligned bounds
    // and a length that is a multiple of twice the SIMD register width.
    Vector* vector_start = AlignFront<Vector>(data);
    Vector* vector_end = AlignBack<Vector>(&data[count]);
    ptrdiff_t total_vectors = vector_end - vector_start;
    if (total_vectors % 2) {
        total_vectors--;
        vector_end--;
    }

    // Only use vector acceleration if
    //  (1) we have a large enough array for it to make a difference, and
    //  (2) the vector region is aligned with |data|
    const ptrdiff_t kMinVectors = 2;
    size_t vector_offset = (uintptr_t) vector_start - (uintptr_t) data;
    if (total_vectors < kMinVectors || vector_offset % sizeof(T) != 0) {
        Reverse(data, count);
        return;
    }

    // We've found a suitable subset. Do the actual swapping.
    for (size_t i = 0; i < total_vectors / 2; i++) {
        Vector v = ReverseVector<T>(vector_start[i]);
        vector_start[i] = ReverseVector<T>(vector_end[-1 - i]);
        vector_end[-1 - i] = v;
    }

    // Our subset of the array is now reversed. But:
    //  (a) There may be unreversed bytes at the beginning and/or end.
    //  (b) The reversed subset may need shifting to its final position.
    size_t vector_end_offset = (uintptr_t) &data[count] -
                                (uintptr_t) vector_end;
    ShiftMiddleAndSwapSides((char*) data, count * sizeof(T),
                            vector_offset, vector_end_offset);

    // Reverse the remaining start and end units. Note that after
    // ShiftMiddleAndSwapSides(), |vector_offset| is the number of unreversed
    // bytes at the *end* of the array.
    Reverse(data, vector_end_offset / sizeof(T));
    size_t remaining_end_units = vector_offset / sizeof(T);
    Reverse(&data[count - remaining_end_units], remaining_end_units);
}

#else // USE_VECTOR

template<typename T>
void MemrevImpl(T* data, size_t count) {
    Reverse(data, count);
}
#endif // USE_VECTOR

} // namespace

void* memrev_reverse(void* data, size_t size, size_t count) {
#ifdef USE_VECTOR
#define CALL_MEMREV_IMPL(WIDTH) \
    MemrevImpl<Vector ## WIDTH>((uint ## WIDTH ##_t*) data, count)
#else
#define CALL_MEMREV_IMPL(WIDTH) \
    MemrevImpl((uint ## WIDTH ##_t*) data, count)
#endif

    switch (size) {
    case 1:
        CALL_MEMREV_IMPL(8);
        break;
    case 2:
        CALL_MEMREV_IMPL(16);
        break;
    case 4:
        CALL_MEMREV_IMPL(32);
        break;
    case 8:
        CALL_MEMREV_IMPL(64);
        break;
    default:
        return NULL;
    }
    return data;
}
<|endoftext|>