<commit_before>/*
 * Copyright (C) 2010-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <urbi/uobject.hh>
#include <libport/foreach.hh>
#include <libport/thread.hh>
#include <libport/lockable.hh>
using namespace urbi;

GD_CATEGORY(Threaded);

/** Threaded UObject.
 *
 * We purposefuly do not use semaphores to wake up our worker thread to
 * increase entropy.
 * This UObject itself is however thread-safe of course.
 */
class Threaded: public UObject
{
public:
  CREATE_CLASS_LOCK
  Threaded(const std::string& n)
  :UObject(n)
  {
    UBindFunction(Threaded, init);
    UBindFunction(Threaded, queueOp);
    UBindFunction(Threaded, getLastRead);
    UBindFunction(Threaded, startThread);
    UBindThreadedFunction(Threaded, throwException, LOCK_NONE);
    UBindThreadedFunction(Threaded, lockNoneDelayOp, LOCK_NONE);
    UBindThreadedFunction(Threaded, lockInstanceDelayOp, LOCK_INSTANCE);
    UBindThreadedFunction(Threaded, lockClassDelayOp, LOCK_CLASS);
    UBindThreadedFunction(Threaded, lockModuleDelayOp, LOCK_MODULE);
    UBindThreadedFunction(Threaded, lockFunctionDelayOp, LOCK_FUNCTION);
    UBindVar(Threaded, updated);
    updated = 0;
    UBindVar(Threaded, timerUpdated);
    timerUpdated = 0;
    UBindVar(Threaded, lastChange);
    lastChange = UList();
    UBindVar(Threaded, lastAccess);
    lastAccess = UList();
    if (n == "Threaded")
      init();
  }
  ~Threaded();
  void lockNoneDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockInstanceDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockFunctionDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockClassDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockModuleDelayOp(int id, int delay) { delayOp(id, delay);}
  void delayOp(int id, int delay);
  void terminate();
  UVar updated;
  UVar timerUpdated;
  UVar lastChange;
  UVar lastAccess;
  void init();
  virtual int update();
  int onChangeDelay(UVar& v);
  int onChange(UVar& v);
  int onAccess(UVar& v);
  void onTimer();
  UValue getLastRead(unsigned id);
  /// Queue asynchronous op on thread \b tid.
  int queueOp(unsigned tid, int op, UList args);
  void throwException(int what);
  /// Start a new thread and return its id
  int startThread();
  // Thread main loop body, returns false when it wants to end.
  bool threadLoopBody(int id);
  // Thread main loop: repeatedly call threadLoopBody.
  void threadLoop(int id);
  int dummy();
  enum OpType
  {
    WRITE_VAR,
    READ_VAR,
    CREATE_VAR,
    DELETE_VAR,
    NOTIFY_CHANGE,
    NOTIFY_ACCESS,
    BIND_FUNCTION,
    SET_UPDATE,
    SET_TIMER,
    UNSET_TIMER,
    UNNOTIFY,
    GETUOBJECT,
    DELAY,
    DIE,
    SET_UOWNED,
    SET_BYPASS,
    WRITE_BINARY,
    EMIT
  };

  struct Operation
  {
    Operation() : op(-1) {}
    Operation(int a, const UList &b)
      : op(a), args(b)
    {}
    int op;
    UList args;
  };
  struct Context
  {
    Context(int id)
    : hasOp(false), dead(false), id(id) {}
    std::list<Operation> ops;
    bool hasOp;
    libport::Lockable opLock;
    std::vector<UVar*> vars;
    std::vector<TimerHandle> timers;
    UValue lastRead;
    pthread_t threadId;
    bool dead;
    int id;
  };
  libport::Lockable opsLock;
  std::vector<Context*> ops;
};

UStart(Threaded);

static const char* opname[] =
  {
    "WRITE_VAR",
    "READ_VAR",
    "CREATE_VAR",
    "DELETE_VAR",
    "NOTIFY_CHANGE",
    "NOTIFY_ACCESS",
    "BIND_FUNCTION",
    "SET_UPDATE",
    "SET_TIMER",
    "UNSET_TIMER",
    "UNNOTIFY",
    "GETUOBJECT",
    "DELAY",
    "DIE",
    "SET_UOWNED",
    "SET_BYPASS",
    "WRITE_BINARY",
    "EMIT",
    0
  };
void Threaded::init()
{
  for (int i=0; opname[i]; ++i)
  {
    UVar v;
    v.init(__name, opname[i]);
    v = i;
  }
}

Threaded::~Threaded()
{
  terminate();
}

void Threaded::terminate()
{
  foreach(Context*c, ops)
  {
    if (!c->dead)
    {
      queueOp(c->id, DIE, UList());
      void* retval;
      std::cerr <<"joining " << c->id << std::endl;
      pthread_join(c->threadId, &retval);
      std::cerr <<"done" << std::endl;
    }
  }
}

int Threaded::queueOp(unsigned tid, int op, UList args)
{
  if (tid >= ops.size())
    return 0;
  libport::BlockLock bl (ops[tid]->opLock);
  ops[tid]->ops.push_back(Operation(op, args));
  ops[tid]->hasOp = true;
  return 1;
}

int Threaded::startThread()
{
  UValue v;
  libport::BlockLock bl (opsLock);
  int id = ops.size();
  ops.push_back(new Context(ops.size()));
  ops.back()->threadId =
    libport::startThread(boost::bind(&Threaded::threadLoop, this, id));
  return id;
}

UValue Threaded::getLastRead(unsigned tid)
{
  if (tid >= ops.size())
    return UValue();
  libport::BlockLock bl (ops[tid]->opLock);
  return ops[tid]->lastRead;
}

void Threaded::delayOp(int id, int delay)
{
  usleep(delay);
  threadLoopBody(id);
}

bool Threaded::threadLoopBody(int id)
{
  #define type0 (op.args[0].type)
  #define string0 (*op.args[0].stringValue)
  #define float0 (op.args[0].val)
  #define int0 static_cast<int>(float0)
  Context* pctx;
  {
    libport::BlockLock bl (opsLock);
    pctx = ops[id];
  }
  Context& ctx = *pctx;
  // Randomize behavior to increase chance of detecting a race condition.
  usleep(rand() % 100000);
  if (ctx.hasOp)
  {
    Operation op;
    {
      libport::BlockLock bl (ctx.opLock);
      op = ctx.ops.front();
      ctx.ops.pop_front();
      if (ctx.ops.empty())
        ctx.hasOp = false;
    }
    GD_FINFO_TRACE("[%s] Executing operation %s", id, op.op);
    switch(op.op)
    {
    case SET_BYPASS:
      ctx.vars[int0]->setBypass(true);
      break;
    case SET_UOWNED:
      ctx.vars[int0]->setOwned();
      break;
    case WRITE_BINARY:
      {
        UBinary b;
        b.type = BINARY_IMAGE;
        b.image.width = 3;
        b.image.height = 3;
        b.image.imageFormat = IMAGE_RGB;
        b.image.size = 9;
        b.image.data = (unsigned char*)const_cast<char*>("abcdefghi");
        *( ctx.vars[int0]) = b;
        b.image.data = 0;
      }
      break;
    case WRITE_VAR:
      if (type0 == DATA_STRING)
      {
        UVar v(string0);
        if (op.args.size() > 2)
          for(int i=0; i<op.args[2].val; ++i)
            v = op.args[1];
        else
          v = op.args[1];
      }
      else
      {
        std::cerr
          << libport::utime()
          << " writevar " << id
          << " " << ctx.vars[int0]->get_name()
          << " " << op.args[1]
          << std::endl;
        *ctx.vars[int0] = op.args[1];
        std::cerr << libport::utime() << "done write " << id << std::endl;
      }
      break;
    case READ_VAR:
      {
        UValue val;
        if (type0 == DATA_STRING)
        {
          UVar v(string0);
          val = v.val();
        }
        else
          val = ctx.vars[int0]->val();
        libport::BlockLock bl (ctx.opLock);
        ctx.lastRead = val;
      }
      break;
    case CREATE_VAR:
      ctx.vars.push_back(new UVar(string0));
      break;
    case DELETE_VAR:
      {
        size_t idx = int0;
        delete ctx.vars[idx];
        if (idx != ctx.vars.size()-1)
          ctx.vars[idx] = ctx.vars[ctx.vars.size()-1];
        ctx.vars.pop_back();
      }
      break;
    case NOTIFY_CHANGE:
      // Bind in async mode if an extra arg is given.
      if (op.args.size() > 1)
        if (type0 == DATA_STRING)
          UNotifyThreadedChange(string0, &Threaded::onChangeDelay,
                                LOCK_FUNCTION);
        else
          UNotifyThreadedChange(*ctx.vars[int0], &Threaded::onChangeDelay,
                                LOCK_FUNCTION);
      else
        if (type0 == DATA_STRING)
          UNotifyChange(string0, &Threaded::onChange);
        else
          UNotifyChange(*ctx.vars[int0], &Threaded::onChange);
      break;
    case NOTIFY_ACCESS:
       if (type0 == DATA_STRING)
        UNotifyAccess(string0, &Threaded::onAccess);
      else
        UNotifyAccess(*ctx.vars[int0], &Threaded::onAccess);
      break;
    case BIND_FUNCTION:
      ::urbi::createUCallback(*this, 0, "function", this,
                        (&Threaded::dummy), __name + "." + string0);
      break;
    case SET_UPDATE:
      USetUpdate(float0);
      break;
    case SET_TIMER:
      ctx.timers.push_back(USetTimer(float0, &Threaded::onTimer));
      break;
    case UNSET_TIMER:
      removeTimer(ctx.timers[int0]);
      if (ctx.timers.size() == 1)
        ctx.timers.pop_back();
      else
      {
        ctx.timers[int0] = ctx.timers.back();
        ctx.timers.pop_back();
      }
      break;
    case UNNOTIFY:
      ctx.vars[int0]->unnotify();
      break;
    case GETUOBJECT:
      {
        UObject* uob = getUObject(string0);
        libport::BlockLock bl (ctx.opLock);
        if (!uob)
          ctx.lastRead =  "0";
        else
          ctx.lastRead = uob->__name;
      }
      break;
    case EMIT:
      {
        UEvent e(string0);
        e.emit(12, 15, "canard");
      }
      break;
    case DELAY:
      usleep(int0);
      break;
    case DIE:
      ctx.dead = true;
      return false;
      break;
    }
    GD_FINFO_TRACE("[%s] Done executing operation %s", id, op.op);
  }
  return true;
}

void Threaded::throwException(int what)
{
  switch(what)
  {
  case 0:
    throw 42;
  default:
    throw std::runtime_error("pan");
  }
}

void Threaded::threadLoop(int id)
{
  while (true)
  {
    try
      {
        if (!threadLoopBody(id))
          return;
      }
    catch(std::exception& e)
      {
        std::cerr <<"exception " << e.what() << std::endl;
      }
    catch(...)
      {
        std::cerr <<"unknown exception" << std::endl;
      }
  }
}

int Threaded::update()
{
  updated = (int)updated + 1;
  return 0;
}

int Threaded::onChangeDelay(UVar& v)
{
  usleep(500000);
  ctx_->lock();
  UList l = lastChange;
  l.array.push_back(new UValue(v.get_name()));
  lastChange = l;
  ctx_->unlock();
  return 0;
}

int Threaded::onChange(UVar& v)
{
  UList l = lastChange;
  l.array.push_back(new UValue(v.get_name()));
  lastChange = l;
  return 0;
}

int Threaded::onAccess(UVar& v)
{
  UList l = lastAccess;
  l.array.push_back(new UValue(v.get_name()));
  lastAccess = l;
  return 0;
};

void Threaded::onTimer()
{
  timerUpdated = (int)timerUpdated + 1;
}

int Threaded::dummy()
{
  return 42;
}
<commit_msg>UObject threaded.<commit_after>/*
 * Copyright (C) 2010-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <urbi/uobject.hh>
#include <libport/foreach.hh>
#include <libport/thread.hh>
#include <libport/lockable.hh>
using namespace urbi;

GD_CATEGORY(Threaded);

/** Threaded UObject.
 *
 * We purposefuly do not use semaphores to wake up our worker thread to
 * increase entropy.
 * This UObject itself is however thread-safe of course.
 */
class Threaded: public UObject
{
public:
  CREATE_CLASS_LOCK
  Threaded(const std::string& n)
  :UObject(n)
  {
    UBindFunction(Threaded, init);
    UBindFunction(Threaded, queueOp);
    UBindFunction(Threaded, getLastRead);
    UBindFunction(Threaded, startThread);
    UBindThreadedFunction(Threaded, throwException, LOCK_NONE);
    UBindThreadedFunction(Threaded, lockNoneDelayOp, LOCK_NONE);
    UBindThreadedFunction(Threaded, lockInstanceDelayOp, LOCK_INSTANCE);
    UBindThreadedFunction(Threaded, lockClassDelayOp, LOCK_CLASS);
    UBindThreadedFunction(Threaded, lockModuleDelayOp, LOCK_MODULE);
    UBindThreadedFunction(Threaded, lockFunctionDelayOp, LOCK_FUNCTION);
    UBindVar(Threaded, updated);
    updated = 0;
    UBindVar(Threaded, timerUpdated);
    timerUpdated = 0;
    UBindVar(Threaded, lastChange);
    lastChange = UList();
    UBindVar(Threaded, lastAccess);
    lastAccess = UList();
    if (n == "Threaded")
      init();
  }
  ~Threaded();
  void lockNoneDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockInstanceDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockFunctionDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockClassDelayOp(int id, int delay) { delayOp(id, delay);}
  void lockModuleDelayOp(int id, int delay) { delayOp(id, delay);}
  void delayOp(int id, int delay);
  void terminate();
  UVar updated;
  UVar timerUpdated;
  UVar lastChange;
  UVar lastAccess;
  void init();
  virtual int update();
  int onChangeDelay(UVar& v);
  int onChange(UVar& v);
  int onAccess(UVar& v);
  void onTimer();
  UValue getLastRead(unsigned id);
  /// Queue asynchronous op on thread \b tid.
  int queueOp(unsigned tid, int op, UList args);
  void throwException(int what);
  /// Start a new thread and return its id
  int startThread();
  // Thread main loop body, returns false when it wants to end.
  bool threadLoopBody(int id);
  // Thread main loop: repeatedly call threadLoopBody.
  void threadLoop(int id);
  int dummy();
  enum OpType
  {
    WRITE_VAR,
    READ_VAR,
    CREATE_VAR,
    DELETE_VAR,
    NOTIFY_CHANGE,
    NOTIFY_ACCESS,
    BIND_FUNCTION,
    SET_UPDATE,
    SET_TIMER,
    UNSET_TIMER,
    UNNOTIFY,
    GETUOBJECT,
    DELAY,
    DIE,
    SET_UOWNED,
    SET_BYPASS,
    WRITE_BINARY,
    EMIT
  };

  struct Operation
  {
    Operation() : op(-1) {}
    Operation(int a, const UList &b)
      : op(a), args(b)
    {}
    int op;
    UList args;
  };
  struct Context
  {
    Context(int id)
    : hasOp(false), dead(false), id(id) {}
    std::list<Operation> ops;
    bool hasOp;
    libport::Lockable opLock;
    std::vector<UVar*> vars;
    std::vector<TimerHandle> timers;
    UValue lastRead;
    pthread_t threadId;
    bool dead;
    int id;
  };
  libport::Lockable opsLock;
  std::vector<Context*> ops;
};

UStart(Threaded);

static const char* opname[] =
  {
    "WRITE_VAR",
    "READ_VAR",
    "CREATE_VAR",
    "DELETE_VAR",
    "NOTIFY_CHANGE",
    "NOTIFY_ACCESS",
    "BIND_FUNCTION",
    "SET_UPDATE",
    "SET_TIMER",
    "UNSET_TIMER",
    "UNNOTIFY",
    "GETUOBJECT",
    "DELAY",
    "DIE",
    "SET_UOWNED",
    "SET_BYPASS",
    "WRITE_BINARY",
    "EMIT",
    0
  };
void Threaded::init()
{
  for (int i=0; opname[i]; ++i)
  {
    UVar v;
    v.init(__name, opname[i]);
    v = i;
  }
}

Threaded::~Threaded()
{
  terminate();
}

void Threaded::terminate()
{
  foreach(Context*c, ops)
  {
    if (!c->dead)
    {
      queueOp(c->id, DIE, UList());
      void* retval;
      std::cerr <<"joining " << c->id << std::endl;
      pthread_join(c->threadId, &retval);
      std::cerr <<"done" << std::endl;
    }
  }
}

int Threaded::queueOp(unsigned tid, int op, UList args)
{
  if (tid >= ops.size())
    return 0;
  libport::BlockLock bl (ops[tid]->opLock);
  ops[tid]->ops.push_back(Operation(op, args));
  ops[tid]->hasOp = true;
  return 1;
}

int Threaded::startThread()
{
  UValue v;
  libport::BlockLock bl (opsLock);
  int id = ops.size();
  ops.push_back(new Context(ops.size()));
  ops.back()->threadId =
    libport::startThread(boost::bind(&Threaded::threadLoop, this, id));
  return id;
}

UValue Threaded::getLastRead(unsigned tid)
{
  if (tid >= ops.size())
    return UValue();
  libport::BlockLock bl (ops[tid]->opLock);
  return ops[tid]->lastRead;
}

void Threaded::delayOp(int id, int delay)
{
  usleep(delay);
  threadLoopBody(id);
}

bool Threaded::threadLoopBody(int id)
{
  #define type0 (op.args[0].type)
  #define string0 (*op.args[0].stringValue)
  #define float0 (op.args[0].val)
  #define int0 static_cast<int>(float0)
  Context* pctx;
  {
    libport::BlockLock bl (opsLock);
    pctx = ops[id];
  }
  Context& ctx = *pctx;
  // Randomize behavior to increase chance of detecting a race condition.
  usleep(rand() % 100000);
  if (ctx.hasOp)
  {
    Operation op;
    {
      libport::BlockLock bl (ctx.opLock);
      op = ctx.ops.front();
      ctx.ops.pop_front();
      if (ctx.ops.empty())
        ctx.hasOp = false;
    }
    GD_FINFO_TRACE("[%s] Executing operation %s", id, op.op);
    switch(op.op)
    {
    case SET_BYPASS:
      ctx.vars[int0]->setBypass(true);
      break;
    case SET_UOWNED:
      ctx.vars[int0]->setOwned();
      break;
    case WRITE_BINARY:
      {
        UBinary b;
        b.type = BINARY_IMAGE;
        b.image.width = 3;
        b.image.height = 3;
        b.image.imageFormat = IMAGE_RGB;
        b.image.size = 9;
        b.image.data = (unsigned char*)const_cast<char*>("abcdefghi");
        *( ctx.vars[int0]) = b;
        b.image.data = 0;
      }
      break;
    case WRITE_VAR:
      if (type0 == DATA_STRING)
      {
        UVar v(string0);
        if (op.args.size() > 2)
          for(int i=0; i<op.args[2].val; ++i)
            v = op.args[1];
        else
          v = op.args[1];
      }
      else
      {
        std::cerr
          << libport::utime()
          << " writevar " << id
          << " " << ctx.vars[int0]->get_name()
          << " " << op.args[1]
          << std::endl;
        *ctx.vars[int0] = op.args[1];
        std::cerr << libport::utime() << "done write " << id << std::endl;
      }
      break;
    case READ_VAR:
      {
        UValue val;
        if (type0 == DATA_STRING)
        {
          UVar v(string0);
          val = v.val();
        }
        else
          val = ctx.vars[int0]->val();
        libport::BlockLock bl (ctx.opLock);
        ctx.lastRead = val;
      }
      break;
    case CREATE_VAR:
      ctx.vars.push_back(new UVar(string0));
      break;
    case DELETE_VAR:
      {
        size_t idx = int0;
        delete ctx.vars[idx];
        if (idx != ctx.vars.size()-1)
          ctx.vars[idx] = ctx.vars[ctx.vars.size()-1];
        ctx.vars.pop_back();
      }
      break;
    case NOTIFY_CHANGE:
      // Bind in async mode if an extra arg is given.
      if (op.args.size() > 1)
        if (type0 == DATA_STRING)
          UNotifyThreadedChange(string0, &Threaded::onChangeDelay,
                                LOCK_FUNCTION);
        else
          UNotifyThreadedChange(*ctx.vars[int0], &Threaded::onChangeDelay,
                                LOCK_FUNCTION);
      else
        if (type0 == DATA_STRING)
          UNotifyChange(string0, &Threaded::onChange);
        else
          UNotifyChange(*ctx.vars[int0], &Threaded::onChange);
      break;
    case NOTIFY_ACCESS:
       if (type0 == DATA_STRING)
        UNotifyAccess(string0, &Threaded::onAccess);
      else
        UNotifyAccess(*ctx.vars[int0], &Threaded::onAccess);
      break;
    case BIND_FUNCTION:
      ::urbi::createUCallback(*this, 0, "function", this,
                        (&Threaded::dummy), __name + "." + string0);
      break;
    case SET_UPDATE:
      USetUpdate(float0);
      break;
    case SET_TIMER:
      ctx.timers.push_back(USetTimer(float0, &Threaded::onTimer));
      break;
    case UNSET_TIMER:
      removeTimer(ctx.timers[int0]);
      if (ctx.timers.size() == 1)
        ctx.timers.pop_back();
      else
      {
        ctx.timers[int0] = ctx.timers.back();
        ctx.timers.pop_back();
      }
      break;
    case UNNOTIFY:
      ctx.vars[int0]->unnotify();
      break;
    case GETUOBJECT:
      {
        UObject* uob = getUObject(string0);
        libport::BlockLock bl (ctx.opLock);
        if (!uob)
          ctx.lastRead =  "0";
        else
          ctx.lastRead = uob->__name;
      }
      break;
    case EMIT:
      {
        UEvent e(string0);
        e.emit(12, 15, "canard");
      }
      break;
    case DELAY:
      usleep(int0);
      break;
    case DIE:
      ctx.dead = true;
      return false;
      break;
    }
    GD_FINFO_TRACE("[%s] Done executing operation %s", id, op.op);
  }
  return true;
}

void Threaded::throwException(int what)
{
  switch(what)
  {
  case 0:
    throw 42;
  default:
    throw std::runtime_error("pan");
  }
}

void Threaded::threadLoop(int id)
{
  while (true)
  {
    try
      {
        if (!threadLoopBody(id))
          return;
      }
    catch(std::exception& e)
      {
        std::cerr <<"exception " << e.what() << std::endl;
      }
    catch(...)
      {
        std::cerr <<"unknown exception" << std::endl;
      }
  }
}

int Threaded::update()
{
  updated = (int)updated + 1;
  return 0;
}

int Threaded::onChangeDelay(UVar& v)
{
  usleep(500000);
  lastChange = v.get_name();
  return 0;
}

int Threaded::onChange(UVar& v)
{
  lastChange = v.get_name();
  return 0;
}

int Threaded::onAccess(UVar& v)
{
  UList l = lastAccess;
  l.array.push_back(new UValue(v.get_name()));
  lastAccess = l;
  return 0;
};

void Threaded::onTimer()
{
  timerUpdated = (int)timerUpdated + 1;
}

int Threaded::dummy()
{
  return 42;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 The Project Oak Authors
 *
 * 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 "oak/server/oak_grpc_node.h"

#include "absl/memory/memory.h"
#include "include/grpcpp/grpcpp.h"
#include "oak/common/logging.h"
#include "oak/server/module_invocation.h"

namespace oak {

std::unique_ptr<OakGrpcNode> OakGrpcNode::Create(
    const std::string& name, NodeId node_id,
    std::shared_ptr<grpc::ServerCredentials> grpc_credentials, const uint16_t port) {
  std::unique_ptr<OakGrpcNode> node = absl::WrapUnique(new OakGrpcNode(name, node_id));

  // Build Server
  grpc::ServerBuilder builder;

  // The default value is "[::]:0", that is used to listen on a free port.
  std::stringstream address;
  address << "[::]:" << port;
  builder.AddListeningPort(address.str(), grpc_credentials, &node->port_);

  // Add a completion queue and a generic service, in order to proxy incoming RPCs to the Oak Node.
  node->completion_queue_ = builder.AddCompletionQueue();

  // Register an async service.
  node->module_service_ = absl::make_unique<grpc::AsyncGenericService>();
  builder.RegisterAsyncGenericService(node->module_service_.get());

  node->server_ = builder.BuildAndStart();
  if (!node->server_) {
    OAK_LOG(FATAL) << "Failed to start gRPC server";
    return nullptr;
  }

  return node;
}

void OakGrpcNode::Start(Handle handle) {
  OAK_LOG(INFO) << "{" << name_ << "} Using handle " << handle << " for sending invocations";
  // Start a new thread to do processing.
  queue_thread_ = std::thread(&OakGrpcNode::Run, this, handle);
}

void OakGrpcNode::Run(Handle handle) {
  OAK_LOG(INFO) << "{" << name_ << "} Starting gRPC completion queue loop on handle " << handle;
  handle_ = handle;

  // The stream object will delete itself when finished with the request,
  // after creating a new stream object for the next request.
  auto stream = new ModuleInvocation(module_service_.get(), completion_queue_.get(), this);
  stream->Start();
  while (true) {
    bool ok;
    void* tag;
    if (!completion_queue_->Next(&tag, &ok)) {
      OAK_LOG(ERROR) << "{" << name_ << "} Failure reading from completion queue";
      return;
    }
    auto callback = static_cast<std::function<void(bool)>*>(tag);
    (*callback)(ok);
    delete callback;
  }
}

void OakGrpcNode::Stop() {
  if (server_) {
    OAK_LOG(INFO) << "{" << name_ << "} Shutting down gRPC server...";
    server_->Shutdown();
  }
  if (completion_queue_ != nullptr) {
    OAK_LOG(INFO) << "{" << name_ << "} Shutting down completion queue...";
    completion_queue_->Shutdown();
  }
  if (queue_thread_.joinable()) {
    OAK_LOG(INFO) << "{" << name_ << "} Waiting for completion of completion queue thread";
    queue_thread_.join();
    OAK_LOG(INFO) << "{" << name_ << "} Completed queue thread";
  }
  // Now there is no separate thread running it's safe to drop the gRPC objects.
  server_ = nullptr;
  completion_queue_ = nullptr;
}

}  // namespace oak
<commit_msg>runtime: add missing library include<commit_after>/*
 * Copyright 2019 The Project Oak Authors
 *
 * 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 "oak/server/oak_grpc_node.h"

#include <sstream>

#include "absl/memory/memory.h"
#include "include/grpcpp/grpcpp.h"
#include "oak/common/logging.h"
#include "oak/server/module_invocation.h"

namespace oak {

std::unique_ptr<OakGrpcNode> OakGrpcNode::Create(
    const std::string& name, NodeId node_id,
    std::shared_ptr<grpc::ServerCredentials> grpc_credentials, const uint16_t port) {
  std::unique_ptr<OakGrpcNode> node = absl::WrapUnique(new OakGrpcNode(name, node_id));

  // Build Server
  grpc::ServerBuilder builder;

  // The default value is "[::]:0", that is used to listen on a free port.
  std::stringstream address;
  address << "[::]:" << port;
  builder.AddListeningPort(address.str(), grpc_credentials, &node->port_);

  // Add a completion queue and a generic service, in order to proxy incoming RPCs to the Oak Node.
  node->completion_queue_ = builder.AddCompletionQueue();

  // Register an async service.
  node->module_service_ = absl::make_unique<grpc::AsyncGenericService>();
  builder.RegisterAsyncGenericService(node->module_service_.get());

  node->server_ = builder.BuildAndStart();
  if (!node->server_) {
    OAK_LOG(FATAL) << "Failed to start gRPC server";
    return nullptr;
  }

  return node;
}

void OakGrpcNode::Start(Handle handle) {
  OAK_LOG(INFO) << "{" << name_ << "} Using handle " << handle << " for sending invocations";
  // Start a new thread to do processing.
  queue_thread_ = std::thread(&OakGrpcNode::Run, this, handle);
}

void OakGrpcNode::Run(Handle handle) {
  OAK_LOG(INFO) << "{" << name_ << "} Starting gRPC completion queue loop on handle " << handle;
  handle_ = handle;

  // The stream object will delete itself when finished with the request,
  // after creating a new stream object for the next request.
  auto stream = new ModuleInvocation(module_service_.get(), completion_queue_.get(), this);
  stream->Start();
  while (true) {
    bool ok;
    void* tag;
    if (!completion_queue_->Next(&tag, &ok)) {
      OAK_LOG(ERROR) << "{" << name_ << "} Failure reading from completion queue";
      return;
    }
    auto callback = static_cast<std::function<void(bool)>*>(tag);
    (*callback)(ok);
    delete callback;
  }
}

void OakGrpcNode::Stop() {
  if (server_) {
    OAK_LOG(INFO) << "{" << name_ << "} Shutting down gRPC server...";
    server_->Shutdown();
  }
  if (completion_queue_ != nullptr) {
    OAK_LOG(INFO) << "{" << name_ << "} Shutting down completion queue...";
    completion_queue_->Shutdown();
  }
  if (queue_thread_.joinable()) {
    OAK_LOG(INFO) << "{" << name_ << "} Waiting for completion of completion queue thread";
    queue_thread_.join();
    OAK_LOG(INFO) << "{" << name_ << "} Completed queue thread";
  }
  // Now there is no separate thread running it's safe to drop the gRPC objects.
  server_ = nullptr;
  completion_queue_ = nullptr;
}

}  // namespace oak
<|endoftext|>


<commit_before>#include <GSObject.h>
#include <GSInteger.h>
#include <GSBool.h>
#include <GSCons.h>
#include <GSTypeTag.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>

void fail()
{
	printf ("FAILED\n");
	exit(1);
}

void testGSObject()
{
	initIntegerTypeTag();
	initBoolTypeTag();
	initConsTypeTag();

	const int ivr = 10;
	GSInteger i1(ivr);
	std::string i1s = i1.typeTag->toString(&i1);
	std::cout << "i1 = " << i1s << std::endl;
	int iv = asInteger(&i1);
	if (iv != ivr)
		fail();
	const bool bvr = true;
	GSBool b1(bvr);
	std::string b1s = b1.typeTag->toString(&b1);
	std::cout << "b1 = " << b1s << std::endl;
	bool bv = asBool(&b1);
	if (bv != bvr)
		fail();

	GSCons cons1(&i1, &b1);
	std::string cons1s = cons1.typeTag->toString(&cons1);
	std::cout << "cons1 = " << cons1s << std::endl;
	if (cons1s != "(10.true)")
		fail();
}

int main(int argc, char *argv[])
{
	printf("running GSObject test...\n");
	testGSObject();
	printf("PASSED\n");
	return 0;
}

<commit_msg>cons test added.<commit_after>#include <GSObject.h>
#include <GSInteger.h>
#include <GSBool.h>
#include <GSCons.h>
#include <GSTypeTag.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>

void fail()
{
	printf ("FAILED\n");
	exit(1);
}

void testGSObject()
{
	initIntegerTypeTag();
	initBoolTypeTag();
	initConsTypeTag();

	const int ivr = 10;
	GSInteger i1(ivr);
	std::string i1s = i1.typeTag->toString(&i1);
	std::cout << "i1 = " << i1s << std::endl;
	int iv = asInteger(&i1);
	if (iv != ivr)
		fail();
	const bool bvr = true;
	GSBool b1(bvr);
	std::string b1s = b1.typeTag->toString(&b1);
	std::cout << "b1 = " << b1s << std::endl;
	bool bv = asBool(&b1);
	if (bv != bvr)
		fail();

	GSCons cons1(&i1, &b1);
	std::string cons1s = cons1.typeTag->toString(&cons1);
	std::cout << "cons1 = " << cons1s << std::endl;
	if (cons1s != "(10.true)")
		fail();

	GSCons *cons2 = (GSCons *)cons(&b1, &i1);
	std::cout << "cons2 = " << cons2->typeTag->toString(cons2)
		<< std::endl;
}

int main(int argc, char *argv[])
{
	printf("running GSObject test...\n");
	testGSObject();
	printf("PASSED\n");
	return 0;
}

<|endoftext|>


<commit_before>/*

  This program will add histograms from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with
     x with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

int main( int argc, char **argv ) {

  if ( argc < 4 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
    cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 source2 [source3 ...]" << endl;
    cout << "This program will add histograms from a list of root files and write them" << endl;
    cout << "to a target root file. The target file is newly created and must not " << endl;
    cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
    cout << "Supply at least two source files for this to make sense... ;-)" << endl;
    cout << "If the first argument is -T, Trees are not merged" <<endl;
    cout << "When -the -f option is specified, one can also specify the compression" <<endl;
    cout << "level of the target file. By default the compression level is 1, but" <<endl;
    cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
    cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
    return 1;
  }
  FileList = new TList();

  Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
  noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
  Int_t newcomp = 1;
  char ft[4];
  for (int j=0;j<9;j++) {
     sprintf(ft,"-f%d",j);
     if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
        force = kTRUE;
         newcomp = j;
        break;
     }
  }

  int ffirst = 2;
  if (force) ffirst++;
  if (noTrees) ffirst++;

  cout << "Target file: " << argv[ffirst-1] << endl;
  Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
  if (!Target || Target->IsZombie()) {
     cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
     cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
     exit(1);
  }
  Target->SetCompressionLevel(newcomp);

  // by default hadd can merge Trees in a file that can go up to 100 Gbytes
  Long64_t maxsize = 100000000; //100GB
  maxsize *= 100;  //to bypass some compiler limitations with big constants
  TTree::SetMaxTreeSize(maxsize);

  for ( int i = ffirst; i < argc; i++ ) {
    cout << "Source file " << i-ffirst+1 << ": " << argv[i] << endl;
    Source = TFile::Open( argv[i] );
    FileList->Add(Source);
  }

  MergeRootfile( Target, FileList,0 );

 //must delete Target to avoid a problem with dictionaries in~ TROOT
  delete Target;

  return 0;
}

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir ) {

  cout << "Target path: " << target->GetPath() << endl;
  TString path( (char*)strstr( target->GetPath(), ":" ) );
  path.Remove( 0, 2 );

  TDirectory *first_source = (TDirectory*)sourcelist->First();
  THashList allNames;
  while(first_source) {
     TDirectory *current_sourcedir = first_source->GetDirectory(path);
     if (!current_sourcedir) {
        first_source = (TDirectory*)sourcelist->After(first_source);
        continue;
     }

     // loop over all keys in this directory
     TChain *globChain = 0;
     TIter nextkey( current_sourcedir->GetListOfKeys() );
     TKey *key, *oldkey=0;
     //gain time, do not add the objects in the list in memory
     TH1::AddDirectory(kFALSE);

     while ( (key = (TKey*)nextkey())) {
        if (current_sourcedir == target) break;
       //keep only the highest cycle number for each key
       if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
       if (allNames.FindObject(key->GetName())) continue;
       allNames.Add(new TObjString(key->GetName()));

       // read object from first source file
       current_sourcedir->cd();
       TObject *obj = key->ReadObj();

       if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
         // descendant of TH1 -> merge it

         TH1 *h1 = (TH1*)obj;
         TList listH;

         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         while ( nextsource ) {

           // make sure we are at the correct directory level by cd'ing to path
           TDirectory *ndir = nextsource->GetDirectory(path);
           if (ndir) {
              ndir->cd();
              TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
              if (key2) {
                 listH.Add(key2->ReadObj());
                 h1->Merge(&listH);
                 listH.Delete();
              }
           }

           nextsource = (TFile*)sourcelist->After( nextsource );
         }
       }
       else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

         // loop over all source files create a chain of Trees "globChain"
         if (!noTrees) {
            TString obj_name;
            if (path.Length()) {
               obj_name = path + "/" + obj->GetName();
            } else {
               obj_name = obj->GetName();
            }

            globChain = new TChain(obj_name);
            globChain->Add(first_source->GetName());
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               //do not add to the list a file that does not contain this Tree
               TFile *curf = TFile::Open(nextsource->GetName());
               if (curf) {
                  Bool_t mustAdd = kFALSE;
                  if (curf->FindKey(obj_name)) {
                     mustAdd = kTRUE;
                  } else {
                     //we could be more clever here. No need to import the object
                     //we are missing a function in TDirectory
                     TObject *aobj = curf->Get(obj_name);
                     if (aobj) { mustAdd = kTRUE; delete aobj;}
                  }
                  if (mustAdd) {
                    globChain->Add(nextsource->GetName());
                  }
               }
               delete curf;
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         }

       } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;
         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist,1);

       } else {

         // object is of no type that we know or can handle
         cout << "Unknown object type, name: "
              << obj->GetName() << " title: " << obj->GetTitle() << endl;
       }

       // now write the merged histogram (which is "in" obj) to the target file
       // note that this will just store obj in the current directory level,
       // which is not persistent until the complete directory itself is stored
       // by "target->Write()" below
       if ( obj ) {
          target->cd();

          //!!if the object is a tree, it is stored in globChain...
          if(obj->IsA()->InheritsFrom( "TDirectory" )) {
             //printf("cas d'une directory\n");
          } else if(obj->IsA()->InheritsFrom( "TTree" )) {
             if (!noTrees) {
                globChain->ls();
                globChain->Merge(target->GetFile(),0,"keep fast");
                delete globChain;
             }
          } else {
             obj->Write( key->GetName() );
          }
       }
       oldkey = key;

     } // while ( ( TKey *key = (TKey*)nextkey() ) )
     first_source = (TDirectory*)sourcelist->After(first_source);
  }
  // save modifications to target file
  target->SaveSelf(kTRUE);
  if (!isdir) sourcelist->Remove(sourcelist->First());
}
<commit_msg>Optimize hadd by clearing the kMustCleanup bit for the temporary histograms.<commit_after>/*

  This program will add histograms from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with
     x with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

int main( int argc, char **argv ) {

  if ( argc < 4 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
    cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 source2 [source3 ...]" << endl;
    cout << "This program will add histograms from a list of root files and write them" << endl;
    cout << "to a target root file. The target file is newly created and must not " << endl;
    cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
    cout << "Supply at least two source files for this to make sense... ;-)" << endl;
    cout << "If the first argument is -T, Trees are not merged" <<endl;
    cout << "When -the -f option is specified, one can also specify the compression" <<endl;
    cout << "level of the target file. By default the compression level is 1, but" <<endl;
    cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
    cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
    return 1;
  }
  FileList = new TList();

  Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
  noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
  Int_t newcomp = 1;
  char ft[4];
  for (int j=0;j<9;j++) {
     sprintf(ft,"-f%d",j);
     if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
        force = kTRUE;
         newcomp = j;
        break;
     }
  }

  int ffirst = 2;
  if (force) ffirst++;
  if (noTrees) ffirst++;

  cout << "Target file: " << argv[ffirst-1] << endl;
  Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
  if (!Target || Target->IsZombie()) {
     cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
     cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
     exit(1);
  }
  Target->SetCompressionLevel(newcomp);

  // by default hadd can merge Trees in a file that can go up to 100 Gbytes
  Long64_t maxsize = 100000000; //100GB
  maxsize *= 100;  //to bypass some compiler limitations with big constants
  TTree::SetMaxTreeSize(maxsize);

  for ( int i = ffirst; i < argc; i++ ) {
    cout << "Source file " << i-ffirst+1 << ": " << argv[i] << endl;
    Source = TFile::Open( argv[i] );
    FileList->Add(Source);
  }

  MergeRootfile( Target, FileList,0 );

 //must delete Target to avoid a problem with dictionaries in~ TROOT
  delete Target;

  return 0;
}

void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir ) {

  cout << "Target path: " << target->GetPath() << endl;
  TString path( (char*)strstr( target->GetPath(), ":" ) );
  path.Remove( 0, 2 );

  TDirectory *first_source = (TDirectory*)sourcelist->First();
  THashList allNames;
  while(first_source) {
     TDirectory *current_sourcedir = first_source->GetDirectory(path);
     if (!current_sourcedir) {
        first_source = (TDirectory*)sourcelist->After(first_source);
        continue;
     }

     // loop over all keys in this directory
     TChain *globChain = 0;
     TIter nextkey( current_sourcedir->GetListOfKeys() );
     TKey *key, *oldkey=0;
     //gain time, do not add the objects in the list in memory
     TH1::AddDirectory(kFALSE);

     while ( (key = (TKey*)nextkey())) {
        if (current_sourcedir == target) break;
       //keep only the highest cycle number for each key
       if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
       if (allNames.FindObject(key->GetName())) continue;
       allNames.Add(new TObjString(key->GetName()));

       // read object from first source file
       current_sourcedir->cd();
       TObject *obj = key->ReadObj();

       if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
         // descendant of TH1 -> merge it

         TH1 *h1 = (TH1*)obj;
         TList listH;

         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         while ( nextsource ) {

           // make sure we are at the correct directory level by cd'ing to path
           TDirectory *ndir = nextsource->GetDirectory(path);
           if (ndir) {
              ndir->cd();
              TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
              if (key2) {
                 TObject *hobj = key2->ReadObj();
                 hobj->ResetBit(kMustCleanup);
                 listH.Add(hobj);
                 h1->Merge(&listH);
                 listH.Delete();
              }
           }

           nextsource = (TFile*)sourcelist->After( nextsource );
         }
       }
       else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

         // loop over all source files create a chain of Trees "globChain"
         if (!noTrees) {
            TString obj_name;
            if (path.Length()) {
               obj_name = path + "/" + obj->GetName();
            } else {
               obj_name = obj->GetName();
            }

            globChain = new TChain(obj_name);
            globChain->Add(first_source->GetName());
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               //do not add to the list a file that does not contain this Tree
               TFile *curf = TFile::Open(nextsource->GetName());
               if (curf) {
                  Bool_t mustAdd = kFALSE;
                  if (curf->FindKey(obj_name)) {
                     mustAdd = kTRUE;
                  } else {
                     //we could be more clever here. No need to import the object
                     //we are missing a function in TDirectory
                     TObject *aobj = curf->Get(obj_name);
                     if (aobj) { mustAdd = kTRUE; delete aobj;}
                  }
                  if (mustAdd) {
                    globChain->Add(nextsource->GetName());
                  }
               }
               delete curf;
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         }

       } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;
         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist,1);

       } else {

         // object is of no type that we know or can handle
         cout << "Unknown object type, name: "
              << obj->GetName() << " title: " << obj->GetTitle() << endl;
       }

       // now write the merged histogram (which is "in" obj) to the target file
       // note that this will just store obj in the current directory level,
       // which is not persistent until the complete directory itself is stored
       // by "target->Write()" below
       if ( obj ) {
          target->cd();

          //!!if the object is a tree, it is stored in globChain...
          if(obj->IsA()->InheritsFrom( "TDirectory" )) {
             //printf("cas d'une directory\n");
          } else if(obj->IsA()->InheritsFrom( "TTree" )) {
             if (!noTrees) {
                globChain->ls();
                globChain->Merge(target->GetFile(),0,"keep fast");
                delete globChain;
             }
          } else {
             obj->Write( key->GetName() );
          }
       }
       oldkey = key;

     } // while ( ( TKey *key = (TKey*)nextkey() ) )
     first_source = (TDirectory*)sourcelist->After(first_source);
  }
  // save modifications to target file
  target->SaveSelf(kTRUE);
  if (!isdir) sourcelist->Remove(sourcelist->First());
}
<|endoftext|>


<commit_before>#include "FOX_OSG_MDIView.h"

#include <osgViewer/ViewerEventHandlers>

#include <osgGA/TrackballManipulator>

#include <osgDB/ReadFile>

// Map
FXDEFMAP(FOX_OSG_MDIView) FOX_OSG_MDIView_Map[] = {
    //________Message_Type_________        ___ID___                        ________Message_Handler________
    FXMAPFUNC(SEL_CHORE,                FOX_OSG_MDIView::ID_CHORE,        FOX_OSG_MDIView::OnIdle)
};

FXIMPLEMENT(FOX_OSG_MDIView, FXMDIChild, FOX_OSG_MDIView_Map, ARRAYNUMBER(FOX_OSG_MDIView_Map))

FOX_OSG_MDIView::FOX_OSG_MDIView(FXMDIClient *p, const FXString &name,
        FXIcon *ic, FXPopup *pup, FXuint opt,
        FXint x, FXint y, FXint w, FXint h)
        :   FXMDIChild(p, name, ic, pup, opt, x, y, w, h)
{
    // A visual to drag OpenGL in double-buffered mode; note the glvisual is
    // shared between all windows which need the same depths and numbers of buffers
    // Thus, while the first visual may take some time to initialize, each subsequent
    // window can be created very quickly; we need to determine grpaphics hardware
    // characteristics only once.
    FXGLVisual* glVisual=new FXGLVisual(getApp(),VISUAL_DOUBLEBUFFER|VISUAL_STEREO);

    m_gwFox = new GraphicsWindowFOX(this, glVisual, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y, x, y, w, h );

    osgViewer::Viewer *viewer = new osgViewer::Viewer;
    viewer->getCamera()->setGraphicsContext(m_gwFox);
    viewer->getCamera()->setViewport(0,0,w,h);
    viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("cow.osg");
    if (!loadedModel)
    {
        return ;
    }

    // add the stats handler
    viewer->addEventHandler(new osgViewer::StatsHandler);

    viewer->setSceneData(loadedModel.get());

    viewer->setCameraManipulator(new osgGA::TrackballManipulator);

    SetViewer(viewer);

    getApp()->addChore(this,ID_CHORE);

}

FOX_OSG_MDIView::~FOX_OSG_MDIView()
{
    getApp()->removeChore(this,ID_CHORE);
}

long FOX_OSG_MDIView::OnIdle(FXObject *sender, FXSelector sel, void* ptr)
{
    m_osgViewer->frame();
    getApp()->addChore(this, ID_CHORE);
    return 1;
}

void FOX_OSG_MDIView::SetViewer(osgViewer::Viewer* viewer)
{
    m_osgViewer = viewer;
}
<commit_msg>Disable the escape sets done on the viewer<commit_after>#include "FOX_OSG_MDIView.h"

#include <osgViewer/ViewerEventHandlers>

#include <osgGA/TrackballManipulator>

#include <osgDB/ReadFile>

// Map
FXDEFMAP(FOX_OSG_MDIView) FOX_OSG_MDIView_Map[] = {
    //________Message_Type_________        ___ID___                        ________Message_Handler________
    FXMAPFUNC(SEL_CHORE,                FOX_OSG_MDIView::ID_CHORE,        FOX_OSG_MDIView::OnIdle)
};

FXIMPLEMENT(FOX_OSG_MDIView, FXMDIChild, FOX_OSG_MDIView_Map, ARRAYNUMBER(FOX_OSG_MDIView_Map))

FOX_OSG_MDIView::FOX_OSG_MDIView(FXMDIClient *p, const FXString &name,
        FXIcon *ic, FXPopup *pup, FXuint opt,
        FXint x, FXint y, FXint w, FXint h)
        :   FXMDIChild(p, name, ic, pup, opt, x, y, w, h)
{
    // A visual to drag OpenGL in double-buffered mode; note the glvisual is
    // shared between all windows which need the same depths and numbers of buffers
    // Thus, while the first visual may take some time to initialize, each subsequent
    // window can be created very quickly; we need to determine grpaphics hardware
    // characteristics only once.
    FXGLVisual* glVisual=new FXGLVisual(getApp(),VISUAL_DOUBLEBUFFER|VISUAL_STEREO);

    m_gwFox = new GraphicsWindowFOX(this, glVisual, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y, x, y, w, h );

    osgViewer::Viewer *viewer = new osgViewer::Viewer;
    viewer->getCamera()->setGraphicsContext(m_gwFox);
    viewer->getCamera()->setViewport(0,0,w,h);
    viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);

    // FOX example does not catch the close of the graphics window, so
    // don't allow the default escape sets to done to be active.
    viewer->setKeyEventSetsDone(0);

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("cow.osg");
    if (!loadedModel)
    {
        return ;
    }

    // add the stats handler
    viewer->addEventHandler(new osgViewer::StatsHandler);

    viewer->setSceneData(loadedModel.get());

    viewer->setCameraManipulator(new osgGA::TrackballManipulator);

    SetViewer(viewer);

    getApp()->addChore(this,ID_CHORE);

}

FOX_OSG_MDIView::~FOX_OSG_MDIView()
{
    getApp()->removeChore(this,ID_CHORE);
}

long FOX_OSG_MDIView::OnIdle(FXObject *sender, FXSelector sel, void* ptr)
{
    m_osgViewer->frame();
    getApp()->addChore(this, ID_CHORE);
    return 1;
}

void FOX_OSG_MDIView::SetViewer(osgViewer::Viewer* viewer)
{
    m_osgViewer = viewer;
}
<|endoftext|>


<commit_before>/*
 *		Classias frontend for training.
 *
 * Copyright (c) 2008,2009 Naoaki Okazaki
 * 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 names of the authors 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.
 */

/* $Id$ */

#ifdef  HAVE_CONFIG_H
#include <config.h>
#endif/*HAVE_CONFIG_H*/

#include <iostream>
#include <classias/version.h>
#include <optparse.h>
#include <tokenize.h>

#include "option.h"

int binary_train(option& opt);
bool binary_usage(option& opt);
int multi_train(option& opt);
bool multi_usage(option& opt);
int candidate_train(option& opt);
bool candidate_usage(option& opt);

class optionparser : public option, public optparse
{
public:
    optionparser(
        std::istream& _is = std::cin,
        std::ostream& _os = std::cout,
        std::ostream& _es = std::cerr
        ) : option(_is, _os, _es)
    {
    }

    BEGIN_OPTION_MAP_INLINE()
        ON_OPTION_WITH_ARG(SHORTOPT('t') || LONGOPT("type"))
            if (strcmp(arg, "binary") == 0 || strcmp(arg, "b") == 0) {
                type = TYPE_BINARY;
            } else if (strcmp(arg, "multi-dense") == 0 || strcmp(arg, "m") == 0) {
                type = TYPE_MULTI_DENSE;
            } else if (strcmp(arg, "multi-sparse") == 0 || strcmp(arg, "n") == 0) {
                type = TYPE_MULTI_SPARSE;
            } else if (strcmp(arg, "candidate") == 0 || strcmp(arg, "c") == 0) {
                type = TYPE_CANDIDATE;
            } else {
                std::stringstream ss;
                ss << "unknown data format specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('a') || LONGOPT("algorithm"))
            if (strcasecmp(arg, "logress") == 0 || strcasecmp(arg, "logress.lbfgs") == 0) {
                algorithm = "logress.lbfgs";
            } else if (strcasecmp(arg, "logress.sgd") == 0) {
                algorithm = "logress.sgd";
            } else {
                std::stringstream ss;
                ss << "unknown training algorithm specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('p') || LONGOPT("set"))
            params.push_back(arg);

        ON_OPTION(SHORTOPT('f') || LONGOPT("shuffle"))
            shuffle = true;

        ON_OPTION(SHORTOPT('b') || LONGOPT("generate-bias"))
            generate_bias = true;

        ON_OPTION_WITH_ARG(SHORTOPT('m') || LONGOPT("model"))
            model = arg;

        ON_OPTION_WITH_ARG(SHORTOPT('g') || LONGOPT("split"))
            split = atoi(arg);

        ON_OPTION_WITH_ARG(SHORTOPT('e') || LONGOPT("holdout"))
            holdout = atoi(arg);

        ON_OPTION(SHORTOPT('x') || LONGOPT("cross-validate"))
            cross_validation = true;

        ON_OPTION_WITH_ARG(SHORTOPT('n') || LONGOPT("negative"))
            negative_labels.insert(arg);

        ON_OPTION_WITH_ARG(SHORTOPT('s') || LONGOPT("token-separator"))
            if (strcmp(arg, " ") == 0 || strcasecmp(arg, "spc") == 0 || strcasecmp(arg, "space") == 0) {
                token_separator = ' ';
            } else if (strcmp(arg, ",") == 0 || strcasecmp(arg, "comma") == 0) {
                token_separator = ',';
            } else if (strcmp(arg, "\t") == 0 || strcasecmp(arg, "tab") == 0) {
                token_separator = '\t';
            } else {
                std::stringstream ss;
                ss << "unknown token separator specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('c') || LONGOPT("value-separator"))
            if (strcmp(arg, ":") == 0 || strcasecmp(arg, "colon") == 0) {
                value_separator = ':';
            } else if (strcmp(arg, "=") == 0 || strcasecmp(arg, "eq") == 0 || strcasecmp(arg, "equal") == 0) {
                value_separator = '=';
            } else if (strcmp(arg, "|") == 0 || strcasecmp(arg, "bar") == 0) {
                value_separator = '|';
            } else {
                std::stringstream ss;
                ss << "unknown value separator specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION(SHORTOPT('h') || LONGOPT("help"))
            mode = MODE_HELP;

        ON_OPTION(SHORTOPT('H') || LONGOPT("help-parameters"))
            mode = MODE_HELP_ALGORITHM;

    END_OPTION_MAP()
};

static void usage(std::ostream& os, const char *argv0)
{
    os << "USAGE: " << argv0 << " [OPTIONS] [DATA1] [DATA2] ..." << std::endl;
    os << "This utility trains a model from training data set(s)." << std::endl;
    os << std::endl;
    os << "  DATA    file(s) corresponding to a data set for training; if multiple N files" << std::endl;
    os << "          are specified, this utility assumes a data set to be split into N" << std::endl;
    os << "          groups and sets a group number (1...N) to the instances in each file;" << std::endl;
    os << "          if no file is specified, the tool reads a data set from STDIN;" << std::endl;
    os << "          if a file name has an extension '.gz', '.bz2', and '.xz', this" << std::endl;
    os << "          utility uses 'gzip', 'bzip2', and 'xv' to decompress the file" << std::endl;
    os << std::endl;
    os << "OPTIONS:" << std::endl;
    os << "  -t, --type=TYPE       specify a task type (DEFAULT='multi-dense'):" << std::endl;
    os << "      b, binary             an instance consists of a boolean class, +1 or -1," << std::endl;
    os << "                            and features" << std::endl;
    os << "      m, multi-dense        an instance consists of a label and attributes;" << std::endl;
    os << "                            features are automatically generated by combining" << std::endl;
    os << "                            possible pairs of attributes and labels regardless" << std::endl;
    os << "                            of the appearances in the training set" << std::endl;
    os << "      n, multi-sparse       an instance consists of a label and attributes;" << std::endl;
    os << "                            features are automatically generated by pairing" << std::endl;
    os << "                            attributes and labels appearing in the training set" << std::endl;
    os << "      c, candidate          an instance begins with a directive line '@boi'" << std::endl;
    os << "                            followed by lines that correspond to multiple" << std::endl;
    os << "                            candidates for the instance; a candidate line" << std::endl;
    os << "                            consists of a class label and features; an instance" << std::endl;
    os << "                            ends with a directive line '@eoi'" << std::endl;
    os << "  -a, --algorithm=NAME  specify a training algorithm (DEFAULT='logress.lbfgs')" << std::endl;
    os << "      logress.lbfgs         logistic regression by L-BFGS method" << std::endl;
    os << "      logress.pegasos       logistic regression by PEGASOS" << std::endl;
    os << "      logress.folos         logistic regression by FOLOS" << std::endl;
    os << "      averaged-perceptron   averaged perceptron" << std::endl;
    os << "  -p, --set=NAME=VALUE  set the algorithm-specific parameter NAME to VALUE;" << std::endl;
    os << "                        use '-H' or '--help-parameters' with the algorithm name" << std::endl;
    os << "                        specified by '-a' or '--algorithm' and the task type" << std::endl;
    os << "                        specified by '-t' or '--type' to see the list of the" << std::endl;
    os << "                        algorithm-specific parameters" << std::endl;
    os << "  -f, --shuffle         shuffle instances in the data" << std::endl;
    os << "  -b, --generate-bias   insert bias features automatically" << std::endl;
    os << "  -m, --model=FILE      store the model to FILE (DEFAULT=''); if the value is" << std::endl;
    os << "                        empty, this utility does not store the model" << std::endl;
    os << "  -g, --split=N         split the instances into N groups; this option is" << std::endl;
    os << "                        useful for holdout evaluation and cross validation" << std::endl;
    os << "  -e, --holdout=M       use the M-th data for holdout evaluation and the rest" << std::endl;
    os << "                        for training" << std::endl;
    os << "  -x, --cross-validate  repeat holdout evaluations for #i in {1, ..., N}" << std::endl;
    os << "                        (N-fold cross validation)" << std::endl;
    os << "  -n, --negative=LABEL  specify a negative label for computing precision," << std::endl;
    os << "                        recall, and F1 scores" << std::endl;
    os << "  -s, --token-separator=SEP assume SEP character as a token separator:" << std::endl;
    os << "      '\t', tab                 a TAB ('\t') character (DEFAULT)" << std::endl;
    os << "      ' ',  spc, space          a SPACE (' ') character" << std::endl;
    os << "      ',',  comma               a COMMA (',') character" << std::endl;
    os << "  -c, --value-separator=SEP assume SEP character as a value separator:" << std::endl;
    os << "      ':',  colon               a COLON (':') character (DEFAULT)" << std::endl;
    os << "      '=',  equal               a EQUAL ('=') character" << std::endl;
    os << "      '|',  bar                 a BAR ('|') character" << std::endl;
    os << "  -h, --help            show this help message and exit" << std::endl;
    os << "  -H, --help-parameters show the help message of algorithm-specific parameters;" << std::endl;
    os << "                        specify an algorithm with '-a' or '--algorithm' option" << std::endl;
    os << std::endl;
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int arg_used = 0;
    optionparser opt;
    std::istream& is = opt.is;
    std::ostream& os = opt.os;
    std::ostream& es = opt.es;

    // Show the copyright information.
    os << CLASSIAS_NAME " ";
    os << CLASSIAS_MAJOR_VERSION << "." << CLASSIAS_MINOR_VERSION << " ";
    os << "trainer ";
    os << CLASSIAS_COPYRIGHT << std::endl;
    os << std::endl;

    // Parse the command-line options.
    try {
        arg_used = opt.parse(argv, argc);
    } catch (const optparse::unrecognized_option& e) {
        es << "ERROR: unrecognized option: " << e.what() << std::endl;
        return 1;
    } catch (const optparse::invalid_value& e) {
        es << "ERROR: " << e.what() << std::endl;
        return 1;
    }

    // Show the help message and exit.
    if (opt.mode == option::MODE_HELP) {
        usage(os, argv[0]);
        return ret;
    } else if (opt.mode == option::MODE_HELP_ALGORITHM) {
        binary_usage(opt) || multi_usage(opt) || candidate_usage(opt);
        return ret;
    }

    // Set the source files.
    for (int i = arg_used;i < argc;++i) {
        opt.files.push_back(argv[i]);
    }

    // Branch for tasks.
    try {
        switch (opt.type) {
        case option::TYPE_BINARY:
            ret = binary_train(opt);
            break;
        case option::TYPE_MULTI_SPARSE:
        case option::TYPE_MULTI_DENSE:
            ret = multi_train(opt);
            break;
        case option::TYPE_CANDIDATE:
            ret = candidate_train(opt);
            break;
        }
    } catch (const std::exception& e) {
        es << "ERROR: " << typeid(e).name() << ": " << e.what() << std::endl;
        return 1;
    }

    return ret;
}
<commit_msg>Tweaked the help message.<commit_after>/*
 *		Classias frontend for training.
 *
 * Copyright (c) 2008,2009 Naoaki Okazaki
 * 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 names of the authors 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.
 */

/* $Id$ */

#ifdef  HAVE_CONFIG_H
#include <config.h>
#endif/*HAVE_CONFIG_H*/

#include <iostream>
#include <classias/version.h>
#include <optparse.h>
#include <tokenize.h>

#include "option.h"

int binary_train(option& opt);
bool binary_usage(option& opt);
int multi_train(option& opt);
bool multi_usage(option& opt);
int candidate_train(option& opt);
bool candidate_usage(option& opt);

class optionparser : public option, public optparse
{
public:
    optionparser(
        std::istream& _is = std::cin,
        std::ostream& _os = std::cout,
        std::ostream& _es = std::cerr
        ) : option(_is, _os, _es)
    {
    }

    BEGIN_OPTION_MAP_INLINE()
        ON_OPTION_WITH_ARG(SHORTOPT('t') || LONGOPT("type"))
            if (strcmp(arg, "binary") == 0 || strcmp(arg, "b") == 0) {
                type = TYPE_BINARY;
            } else if (strcmp(arg, "multi-dense") == 0 || strcmp(arg, "m") == 0) {
                type = TYPE_MULTI_DENSE;
            } else if (strcmp(arg, "multi-sparse") == 0 || strcmp(arg, "n") == 0) {
                type = TYPE_MULTI_SPARSE;
            } else if (strcmp(arg, "candidate") == 0 || strcmp(arg, "c") == 0) {
                type = TYPE_CANDIDATE;
            } else {
                std::stringstream ss;
                ss << "unknown data format specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('a') || LONGOPT("algorithm"))
            if (strcasecmp(arg, "logress") == 0 || strcasecmp(arg, "logress.lbfgs") == 0) {
                algorithm = "logress.lbfgs";
            } else if (strcasecmp(arg, "logress.sgd") == 0) {
                algorithm = "logress.sgd";
            } else {
                std::stringstream ss;
                ss << "unknown training algorithm specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('p') || LONGOPT("set"))
            params.push_back(arg);

        ON_OPTION(SHORTOPT('f') || LONGOPT("shuffle"))
            shuffle = true;

        ON_OPTION(SHORTOPT('b') || LONGOPT("generate-bias"))
            generate_bias = true;

        ON_OPTION_WITH_ARG(SHORTOPT('m') || LONGOPT("model"))
            model = arg;

        ON_OPTION_WITH_ARG(SHORTOPT('g') || LONGOPT("split"))
            split = atoi(arg);

        ON_OPTION_WITH_ARG(SHORTOPT('e') || LONGOPT("holdout"))
            holdout = atoi(arg);

        ON_OPTION(SHORTOPT('x') || LONGOPT("cross-validate"))
            cross_validation = true;

        ON_OPTION_WITH_ARG(SHORTOPT('n') || LONGOPT("negative"))
            negative_labels.insert(arg);

        ON_OPTION_WITH_ARG(SHORTOPT('s') || LONGOPT("token-separator"))
            if (strcmp(arg, " ") == 0 || strcasecmp(arg, "spc") == 0 || strcasecmp(arg, "space") == 0) {
                token_separator = ' ';
            } else if (strcmp(arg, ",") == 0 || strcasecmp(arg, "comma") == 0) {
                token_separator = ',';
            } else if (strcmp(arg, "\t") == 0 || strcasecmp(arg, "tab") == 0) {
                token_separator = '\t';
            } else {
                std::stringstream ss;
                ss << "unknown token separator specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION_WITH_ARG(SHORTOPT('c') || LONGOPT("value-separator"))
            if (strcmp(arg, ":") == 0 || strcasecmp(arg, "colon") == 0) {
                value_separator = ':';
            } else if (strcmp(arg, "=") == 0 || strcasecmp(arg, "eq") == 0 || strcasecmp(arg, "equal") == 0) {
                value_separator = '=';
            } else if (strcmp(arg, "|") == 0 || strcasecmp(arg, "bar") == 0) {
                value_separator = '|';
            } else {
                std::stringstream ss;
                ss << "unknown value separator specified: " << arg;
                throw invalid_value(ss.str());
            }

        ON_OPTION(SHORTOPT('h') || LONGOPT("help"))
            mode = MODE_HELP;

        ON_OPTION(SHORTOPT('H') || LONGOPT("help-parameters"))
            mode = MODE_HELP_ALGORITHM;

    END_OPTION_MAP()
};

static void usage(std::ostream& os, const char *argv0)
{
    os << "USAGE: " << argv0 << " [OPTIONS] [DATA1] [DATA2] ..." << std::endl;
    os << "This utility trains a model from training data set(s)." << std::endl;
    os << std::endl;
    os << "  DATA    file(s) corresponding to a data set for training; if multiple N files" << std::endl;
    os << "          are specified, this utility assumes a data set to be split into N" << std::endl;
    os << "          groups and sets a group number (1...N) to the instances in each file;" << std::endl;
    os << "          if no file is specified, the tool reads a data set from STDIN;" << std::endl;
    os << "          if a file name has an extension '.gz', '.bz2', and '.xz', the utility" << std::endl;
    os << "          uses 'gzip', 'bzip2', and 'xv' to decompress the input file" << std::endl;
    os << std::endl;
    os << "OPTIONS:" << std::endl;
    os << "  -t, --type=TYPE       specify a task type (DEFAULT='multi-dense'):" << std::endl;
    os << "      b, binary             an instance consists of a boolean class, +1 or -1," << std::endl;
    os << "                            and features" << std::endl;
    os << "      m, multi-dense        an instance consists of a label and attributes;" << std::endl;
    os << "                            features are automatically generated by combining" << std::endl;
    os << "                            possible pairs of attributes and labels regardless" << std::endl;
    os << "                            of the appearances in the training set" << std::endl;
    os << "      n, multi-sparse       an instance consists of a label and attributes;" << std::endl;
    os << "                            features are automatically generated by pairing" << std::endl;
    os << "                            attributes and labels appearing in the training set" << std::endl;
    os << "      c, candidate          an instance begins with a directive line '@boi'" << std::endl;
    os << "                            followed by lines that correspond to multiple" << std::endl;
    os << "                            candidates for the instance; a candidate line" << std::endl;
    os << "                            consists of a class label and features; an instance" << std::endl;
    os << "                            ends with a directive line '@eoi'" << std::endl;
    os << "  -a, --algorithm=NAME  specify a training algorithm (DEFAULT='logress.lbfgs')" << std::endl;
    os << "      logress.lbfgs         logistic regression by L-BFGS method" << std::endl;
    os << "      logress.pegasos       logistic regression by PEGASOS" << std::endl;
    os << "      logress.folos         logistic regression by FOLOS" << std::endl;
    os << "      averaged-perceptron   averaged perceptron" << std::endl;
    os << "  -p, --set=NAME=VALUE  set the algorithm-specific parameter NAME to VALUE;" << std::endl;
    os << "                        use '-H' or '--help-parameters' with the algorithm name" << std::endl;
    os << "                        specified by '-a' or '--algorithm' and the task type" << std::endl;
    os << "                        specified by '-t' or '--type' to see the list of the" << std::endl;
    os << "                        algorithm-specific parameters" << std::endl;
    os << "  -f, --shuffle         shuffle instances in the data" << std::endl;
    os << "  -b, --generate-bias   insert bias features automatically" << std::endl;
    os << "  -m, --model=FILE      store the model to FILE (DEFAULT=''); if the value is" << std::endl;
    os << "                        empty, this utility does not store the model" << std::endl;
    os << "  -g, --split=N         split the instances into N groups; this option is" << std::endl;
    os << "                        useful for holdout evaluation and cross validation" << std::endl;
    os << "  -e, --holdout=M       use the M-th data for holdout evaluation and the rest" << std::endl;
    os << "                        for training" << std::endl;
    os << "  -x, --cross-validate  repeat holdout evaluations for #i in {1, ..., N}" << std::endl;
    os << "                        (N-fold cross validation)" << std::endl;
    os << "  -n, --negative=LABEL  specify a negative label for computing precision," << std::endl;
    os << "                        recall, and F1 scores" << std::endl;
    os << "  -s, --token-separator=SEP assume SEP character as a token separator:" << std::endl;
    os << "      '\t', tab                 a TAB ('\t') character (DEFAULT)" << std::endl;
    os << "      ' ',  spc, space          a SPACE (' ') character" << std::endl;
    os << "      ',',  comma               a COMMA (',') character" << std::endl;
    os << "  -c, --value-separator=SEP assume SEP character as a value separator:" << std::endl;
    os << "      ':',  colon               a COLON (':') character (DEFAULT)" << std::endl;
    os << "      '=',  equal               a EQUAL ('=') character" << std::endl;
    os << "      '|',  bar                 a BAR ('|') character" << std::endl;
    os << "  -h, --help            show this help message and exit" << std::endl;
    os << "  -H, --help-parameters show the help message of algorithm-specific parameters;" << std::endl;
    os << "                        specify an algorithm with '-a' or '--algorithm' option" << std::endl;
    os << std::endl;
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int arg_used = 0;
    optionparser opt;
    std::istream& is = opt.is;
    std::ostream& os = opt.os;
    std::ostream& es = opt.es;

    // Show the copyright information.
    os << CLASSIAS_NAME " ";
    os << CLASSIAS_MAJOR_VERSION << "." << CLASSIAS_MINOR_VERSION << " ";
    os << "trainer ";
    os << CLASSIAS_COPYRIGHT << std::endl;
    os << std::endl;

    // Parse the command-line options.
    try {
        arg_used = opt.parse(argv, argc);
    } catch (const optparse::unrecognized_option& e) {
        es << "ERROR: unrecognized option: " << e.what() << std::endl;
        return 1;
    } catch (const optparse::invalid_value& e) {
        es << "ERROR: " << e.what() << std::endl;
        return 1;
    }

    // Show the help message and exit.
    if (opt.mode == option::MODE_HELP) {
        usage(os, argv[0]);
        return ret;
    } else if (opt.mode == option::MODE_HELP_ALGORITHM) {
        binary_usage(opt) || multi_usage(opt) || candidate_usage(opt);
        return ret;
    }

    // Set the source files.
    for (int i = arg_used;i < argc;++i) {
        opt.files.push_back(argv[i]);
    }

    // Branch for tasks.
    try {
        switch (opt.type) {
        case option::TYPE_BINARY:
            ret = binary_train(opt);
            break;
        case option::TYPE_MULTI_SPARSE:
        case option::TYPE_MULTI_DENSE:
            ret = multi_train(opt);
            break;
        case option::TYPE_CANDIDATE:
            ret = candidate_train(opt);
            break;
        }
    } catch (const std::exception& e) {
        es << "ERROR: " << typeid(e).name() << ": " << e.what() << std::endl;
        return 1;
    }

    return ret;
}
<|endoftext|>


<commit_before>#include <ostream>
#include "linalg/util.h"
#include "render/color.h"

Color24::Color24(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}

Colorf::Colorf(float r, float g, float b) : r(r), g(g), b(b) {
	normalize();
}
void Colorf::normalize(){
	r = clamp(r, 0.f, 1.f);
	g = clamp(g, 0.f, 1.f);
	b = clamp(b, 0.f, 1.f);
}
Colorf& Colorf::operator+=(const Colorf &c){
	r += c.r;
	b += c.b;
	g += c.g;
	return *this;
}
Colorf& Colorf::operator-=(const Colorf &c){
	r -= c.r;
	b -= c.b;
	g -= c.g;
	return *this;
}
Colorf& Colorf::operator*=(float s){
	r *= s;
	b *= s;
	g *= s;
	return *this;
}
Colorf& Colorf::operator/=(float s){
	return *this *= 1.f / s;
}
Colorf::operator Color24() const {
	return Color24(static_cast<uint8_t>(r * 255), static_cast<uint8_t>(g * 255),
		static_cast<uint8_t>(b * 255));
}
Colorf operator+(const Colorf &a, const Colorf &b){
	return Colorf{a.r + b.r, a.g + b.g, a.b + b.b};
}
Colorf operator-(const Colorf &a, const Colorf &b){
	return Colorf{a.r - b.r, a.g - b.g, a.b - b.b};
}
Colorf operator*(const Colorf &a, const Colorf &b){
	return Colorf{a.r * b.r, a.g * b.g, a.b * b.b};
}
Colorf operator*(const Colorf &a, float s){
	return Colorf{a.r * s, a.g * s, a.b * s};
}
Colorf operator*(float s, const Colorf &a){
	return Colorf{a.r * s, a.g * s, a.b * s};
}
Colorf operator/(const Colorf &c, float s){
	float inv_s = 1.f / s;
	return c * inv_s;
}
bool operator==(const Colorf &a, const Colorf &b){
	return a.r == b.r && a.g == b.g && a.b == b.b;
}
bool operator!=(const Colorf &a, const Colorf &b){
	return !(a == b);
}
std::ostream& operator<<(std::ostream &os, const Colorf &c){
	os << "Colorf: [r = " << c.r << ", g = " << c.g
		<< ", b = " << c.b << "] ";
	return os;
}

<commit_msg>Setup a situation with all 8 threads conflicting on every pixel<commit_after>#include <ostream>
#include "linalg/util.h"
#include "render/color.h"

Color24::Color24(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}

Colorf::Colorf(float r, float g, float b) : r(r), g(g), b(b){}
void Colorf::normalize(){
	r = clamp(r, 0.f, 1.f);
	g = clamp(g, 0.f, 1.f);
	b = clamp(b, 0.f, 1.f);
}
Colorf& Colorf::operator+=(const Colorf &c){
	r += c.r;
	b += c.b;
	g += c.g;
	return *this;
}
Colorf& Colorf::operator-=(const Colorf &c){
	r -= c.r;
	b -= c.b;
	g -= c.g;
	return *this;
}
Colorf& Colorf::operator*=(float s){
	r *= s;
	b *= s;
	g *= s;
	return *this;
}
Colorf& Colorf::operator/=(float s){
	return *this *= 1.f / s;
}
Colorf::operator Color24() const {
	return Color24(static_cast<uint8_t>(r * 255), static_cast<uint8_t>(g * 255),
		static_cast<uint8_t>(b * 255));
}
Colorf operator+(const Colorf &a, const Colorf &b){
	return Colorf{a.r + b.r, a.g + b.g, a.b + b.b};
}
Colorf operator-(const Colorf &a, const Colorf &b){
	return Colorf{a.r - b.r, a.g - b.g, a.b - b.b};
}
Colorf operator*(const Colorf &a, const Colorf &b){
	return Colorf{a.r * b.r, a.g * b.g, a.b * b.b};
}
Colorf operator*(const Colorf &a, float s){
	return Colorf{a.r * s, a.g * s, a.b * s};
}
Colorf operator*(float s, const Colorf &a){
	return Colorf{a.r * s, a.g * s, a.b * s};
}
Colorf operator/(const Colorf &c, float s){
	float inv_s = 1.f / s;
	return c * inv_s;
}
bool operator==(const Colorf &a, const Colorf &b){
	return a.r == b.r && a.g == b.g && a.b == b.b;
}
bool operator!=(const Colorf &a, const Colorf &b){
	return !(a == b);
}
std::ostream& operator<<(std::ostream &os, const Colorf &c){
	os << "Colorf: [r = " << c.r << ", g = " << c.g
		<< ", b = " << c.b << "] ";
	return os;
}

<|endoftext|>