<commit_before>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include <cstdlib>
#include <cstdio>

#include "monarch/app/App.h"
#include "monarch/app/AppPluginFactory.h"
#include "monarch/app/ConfigPlugin.h"
#include "monarch/app/LoggingPlugin.h"
#include "monarch/app/MonarchPlugin.h"
#include "monarch/app/KernelPlugin.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/event/EventWaiter.h"
#include "monarch/logging/Logging.h"

#include "monarch/app/KernelPlugin.h"

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::io;
using namespace monarch::kernel;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;

#define PLUGIN_NAME "monarch.app.Kernel"
#define PLUGIN_CL_CFG_ID PLUGIN_NAME ".commandLine"

KernelPlugin::KernelPlugin() :
   mState(Stopped),
   mKernel(NULL)
{
}

KernelPlugin::~KernelPlugin()
{
}

bool KernelPlugin::initMetaConfig(Config& meta)
{
   bool rval = monarch::app::AppPlugin::initMetaConfig(meta);

   // defaults
   if(rval)
   {
      Config& c =
         App::makeMetaConfig(meta, PLUGIN_NAME ".defaults", "defaults")
            [ConfigManager::MERGE][PLUGIN_NAME];
      // modulePath is a map of arrays
      // Keys are unique per module path source to allow for configured other
      // lists of paths. Values are arrays of files or dirs to load.
      c["modulePath"]->setType(Map);
      c["env"] = true;
      c["printModuleVersions"] = false;
      c["maxThreadCount"] = UINT32_C(100);
      c["maxConnectionCount"] = UINT32_C(100);
      // waitEvents is a map of arrays of event ids. The map keys should be
      // unique such as plugin ids. The kernel will wait for all these events
      // to occur before exiting. (Some special kernel events also can cause
      // a quicker exit.)
      c["waitEvents"]->setType(Map);
   }

   // command line options
   if(rval)
   {
      Config& c = App::makeMetaConfig(
         meta, PLUGIN_CL_CFG_ID, "command line", "options")
            [ConfigManager::MERGE][PLUGIN_NAME];
      c["modulePath"][PLUGIN_CL_CFG_ID]->setType(Array);
   }

   return rval;
}

DynamicObject KernelPlugin::getCommandLineSpecs()
{
   DynamicObject spec;
   spec["help"] =
"Module options:\n"
"  -m, --module-path PATH\n"
"                      A colon separated list of module files, directories of\n"
"                      modules, y list where extension modules\n"
"                      are stored. May be specified multiple times.\n"
"                      Loaded after modules in MONARCH_MODULE_PATH.\n"
"      --no-module-path-env\n"
"                      Disable MONARCH_MODULE_PATH.\n"
"      --module-versions\n"
"                      Prints the module versions.\n"
"\n";

   DynamicObject opt;
   Config& options = getApp()->getMetaConfig()
      ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE];
   Config& configOptions = options[PLUGIN_NAME];

   opt = spec["options"]->append();
   opt["short"] = "-m";
   opt["long"] = "--module-path";
   opt["append"] = configOptions["modulePath"][PLUGIN_CL_CFG_ID];
   opt["argError"] = "No path specified.";

   opt = spec["options"]->append();
   opt["long"] = "--no-module-path-env";
   opt["setFalse"]["root"] = configOptions;
   opt["setFalse"]["path"] = "env";

   opt = spec["options"]->append();
   opt["long"] = "--module-versions";
   opt["setTrue"]["root"] = configOptions;
   opt["setTrue"]["path"] = "printModuleVersions";

   DynamicObject specs = AppPlugin::getCommandLineSpecs();
   specs->append(spec);
   return specs;
}

bool KernelPlugin::didParseCommandLine()
{
   bool rval = AppPlugin::didParseCommandLine();

   // process flags
   // only done after bootstrap mode so that all modules info is available
   if(rval && getApp()->getMode() != App::BOOTSTRAP)
   {
      Config& cfg = getApp()->getMetaConfig()
         ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE][PLUGIN_NAME];

      if(cfg["printModuleVersions"]->getBoolean())
      {
         // FIXME: print out module info
         /*
         printf("%s v%s\n", ...);
         // Raise known exit exception.
         ExceptionRef e = new Exception(
            "Module versions printed.",
            "monarch.app.Exit", EXIT_SUCCESS);
         Exception::set(e);
         rval = false;
         */
         ExceptionRef e = new Exception(
            "Not implemented.",
            "monarch.app.NotImplemented", EXIT_FAILURE);
         Exception::set(e);
         rval = false;
      }
   }

   return rval;
}

bool KernelPlugin::runApp()
{
   bool rval = true;

   mState = Starting;
   while(mState == Starting || mState == Restarting)
   {
      // [re]start the node
      MO_CAT_INFO(MO_KERNEL_CAT,
         (mState == Restarting) ?
            "Restarting kernel..." : "Starting kernel...");

      // get kernel config
      Config cfg = getApp()->getConfig()[PLUGIN_NAME];
      App* app = new App;

      // create and start kernel
      mKernel = new MicroKernel();
      mKernel->setConfigManager(app->getConfigManager(), false);
      mKernel->setFiberScheduler(new FiberScheduler(), true);
      mKernel->setFiberMessageCenter(new FiberMessageCenter(), true);
      mKernel->setEventController(new EventController(), true);
      mKernel->setEventDaemon(new EventDaemon(), true);
      mKernel->setServer(new Server(), true);

      // set thread and connection limits
      mKernel->setMaxAuxiliaryThreads(cfg["maxThreadCount"]->getUInt32());
      mKernel->setMaxServerConnections(cfg["maxConnectionCount"]->getUInt32());

      rval = mKernel->start();
      if(rval)
      {
         rval =
            mKernel->loadModule(
               createMonarchPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createConfigPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createLoggingPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createKernelPluginFactory, freeAppPluginFactory);

         // FIXME: in did load configs should add env paths to config

         // Collect all module paths so they can be loaded in bulk.
         // This helps to avoid issues with needing to specify load order
         // explicitly.
         FileList modulePaths;
         ConfigIterator mpMods = cfg["modulePath"].getIterator();
         while(rval && mpMods->hasNext())
         {
            ConfigIterator mpPaths = mpMods->next().getIterator();
            while(rval && mpPaths->hasNext())
            {
               const char* path = mpPaths->next()->getString();
               FileList pathList = File::parsePath(path);
               modulePaths->concat(*pathList);
            }
         }
         // load all module paths at once
         rval = mKernel->loadModules(modulePaths);

         if(!rval)
         {
            MO_CAT_INFO(MO_KERNEL_CAT, "Stopping kernel due to exception.");
            mKernel->stop();
         }
      }
      mState = Running;

      if(rval)
      {
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel started.");

         // send ready event
         {
            Event e;
            e["type"] = "monarch.kernel.Kernel.ready";
            mKernel->getEventController()->schedule(e);
         }

         if(rval)
         {
            {
               // create AppPlugins from all loaded AppPluginFactories
               MicroKernel::ModuleApiList factories;
               mKernel->getModuleApisByType(
                  "monarch.app.AppPluginFactory", factories);
               for(MicroKernel::ModuleApiList::iterator i = factories.begin();
                  rval && i != factories.end(); i++)
               {
                  ModuleId id = dynamic_cast<Module*>(*i)->getId();
                  AppPluginFactory* f = dynamic_cast<AppPluginFactory*>(*i);
                  AppPluginRef p = f->createAppPlugin();
                  MO_CAT_OBJECT_INFO(
                     MO_KERNEL_CAT, app,
                     "Adding AppPlugin to App: %s v%s.", id.name, id.version);
                  rval = app->addPlugin(p);
               }
            }

            // waiter for kernel and plugin events
            // used to wait for plugins to complete or for kernel control events
            EventWaiter waiter(mKernel->getEventController());
            // wait for generic kernel events
            waiter.start("monarch.kernel.Kernel.shutdown");
            waiter.start("monarch.kernel.Kernel.restart");

            // collect event counts and start waiting for them
            // make a map of event ids to a counter
            DynamicObject waitEvents;
            waitEvents->setType(Map);
            // get the event config
            {
               // map of arrays of event ids
               Config cfgWaitEvents =
                  getApp()->getConfig()[PLUGIN_NAME]["waitEvents"];
               DynamicObjectIterator i = cfgWaitEvents.getIterator();
               while(i->hasNext())
               {
                  DynamicObjectIterator ii = i->next().getIterator();
                  while(ii->hasNext())
                  {
                     const char* type = i->next()->getString();
                     uint32_t count = 1;
                     if(waitEvents->hasMember(type))
                     {
                        count += waitEvents[type]->getUInt32();
                     }
                     waitEvents[type] = count;
                     // first time seeing event, start waiting for it
                     if(count == 1)
                     {
                        waiter.start(type);
                     }
                  }
               }
            }

            int status;
            if(rval)
            {
               // run sub app
               status = app->start(getApp()->getCommandLine());
               rval = (status == EXIT_SUCCESS);
            }

            // wait for events if app started successfully
            // checking for exception in case of success with an exit exception
            if(rval && !Exception::isSet())
            {
               while(mState == Running && waitEvents->length() != 0)
               {
                  waiter.waitForEvent();
                  Event e = waiter.popEvent();
                  const char* type = e["type"]->getString();
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "EventWaiter got event: %s", type);
                  if(strcmp("monarch.kernel.Kernel.shutdown", type) == 0)
                  {
                     mState = Stopping;
                  }
                  else if(strcmp("monarch.kernel.Kernel.restart", type) == 0)
                  {
                     mState = Restarting;
                  }
                  else
                  {
                     if(waitEvents->hasMember(type))
                     {
                        uint32_t count = waitEvents[type]->getUInt32();
                        count--;
                        if(count == 0)
                        {
                           waitEvents->removeMember(type);
                        }
                        else
                        {
                           waitEvents[type] = count;
                        }
                     }
                  }
               }
               mState = Stopping;
            }

            if(!rval)
            {
               getApp()->setExitStatus(app->getExitStatus());
            }
         }

         delete app;
         app = NULL;

         // FIXME: actually stopping microkernel, not just node
         // stop node
         MO_CAT_INFO(MO_KERNEL_CAT,
            (mState == Restarting) ?
               "Stopping kernel for restart..." :
               "Stopping kernel...");
         mKernel->stop();
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel stopped.");
         // set to stopped unless restarting
         mState = (mState == Stopping) ? Stopped : mState;
      }
      else
      {
         MO_CAT_ERROR(MO_KERNEL_CAT, "Kernel start failed: %s",
            JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str());
      }

      if(app != NULL)
      {
         delete app;
         app = NULL;
      }

      // clean up kernel
      delete mKernel;
      mKernel = NULL;
   }

   return rval;
}

bool KernelPlugin::run()
{
   bool rval = AppPlugin::run();
   if(rval && getApp()->getMode() == App::BOOTSTRAP)
   {
      rval = runApp();
   }
   return rval;
}

class KernelPluginFactory :
   public AppPluginFactory
{
public:
   KernelPluginFactory() :
      AppPluginFactory(PLUGIN_NAME, "1.0")
   {
      addDependency("monarch.app.Config", "1.0");
      addDependency("monarch.app.Logging", "1.0");
   }

   virtual ~KernelPluginFactory() {}

   virtual AppPluginRef createAppPlugin()
   {
      return new KernelPlugin();
   }
};

Module* monarch::app::createKernelPluginFactory()
{
   return new KernelPluginFactory();
}
<commit_msg>Fix typos and text of command line option help.<commit_after>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_CONSTANT_MACROS

#include <cstdlib>
#include <cstdio>

#include "monarch/app/App.h"
#include "monarch/app/AppPluginFactory.h"
#include "monarch/app/ConfigPlugin.h"
#include "monarch/app/LoggingPlugin.h"
#include "monarch/app/MonarchPlugin.h"
#include "monarch/app/KernelPlugin.h"
#include "monarch/data/json/JsonWriter.h"
#include "monarch/event/EventWaiter.h"
#include "monarch/logging/Logging.h"

#include "monarch/app/KernelPlugin.h"

using namespace std;
using namespace monarch::app;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::io;
using namespace monarch::kernel;
using namespace monarch::logging;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;

#define PLUGIN_NAME "monarch.app.Kernel"
#define PLUGIN_CL_CFG_ID PLUGIN_NAME ".commandLine"

KernelPlugin::KernelPlugin() :
   mState(Stopped),
   mKernel(NULL)
{
}

KernelPlugin::~KernelPlugin()
{
}

bool KernelPlugin::initMetaConfig(Config& meta)
{
   bool rval = monarch::app::AppPlugin::initMetaConfig(meta);

   // defaults
   if(rval)
   {
      Config& c =
         App::makeMetaConfig(meta, PLUGIN_NAME ".defaults", "defaults")
            [ConfigManager::MERGE][PLUGIN_NAME];
      // modulePath is a map of arrays
      // Keys are unique per module path source to allow for configured other
      // lists of paths. Values are arrays of files or dirs to load.
      c["modulePath"]->setType(Map);
      c["env"] = true;
      c["printModuleVersions"] = false;
      c["maxThreadCount"] = UINT32_C(100);
      c["maxConnectionCount"] = UINT32_C(100);
      // waitEvents is a map of arrays of event ids. The map keys should be
      // unique such as plugin ids. The kernel will wait for all these events
      // to occur before exiting. (Some special kernel events also can cause
      // a quicker exit.)
      c["waitEvents"]->setType(Map);
   }

   // command line options
   if(rval)
   {
      Config& c = App::makeMetaConfig(
         meta, PLUGIN_CL_CFG_ID, "command line", "options")
            [ConfigManager::MERGE][PLUGIN_NAME];
      c["modulePath"][PLUGIN_CL_CFG_ID]->setType(Array);
   }

   return rval;
}

DynamicObject KernelPlugin::getCommandLineSpecs()
{
   DynamicObject spec;
   spec["help"] =
"Module options:\n"
"  -m, --module-path PATH\n"
"                      A colon separated list of modules or directories where\n"
"                      modules are stored. May be specified multiple times.\n"
"                      Loaded after modules in MONARCH_MODULE_PATH.\n"
"      --no-module-path-env\n"
"                      Disable MONARCH_MODULE_PATH.\n"
"      --module-versions\n"
"                      Prints the module versions.\n"
"\n";

   DynamicObject opt;
   Config& options = getApp()->getMetaConfig()
      ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE];
   Config& configOptions = options[PLUGIN_NAME];

   opt = spec["options"]->append();
   opt["short"] = "-m";
   opt["long"] = "--module-path";
   opt["append"] = configOptions["modulePath"][PLUGIN_CL_CFG_ID];
   opt["argError"] = "No path specified.";

   opt = spec["options"]->append();
   opt["long"] = "--no-module-path-env";
   opt["setFalse"]["root"] = configOptions;
   opt["setFalse"]["path"] = "env";

   opt = spec["options"]->append();
   opt["long"] = "--module-versions";
   opt["setTrue"]["root"] = configOptions;
   opt["setTrue"]["path"] = "printModuleVersions";

   DynamicObject specs = AppPlugin::getCommandLineSpecs();
   specs->append(spec);
   return specs;
}

bool KernelPlugin::didParseCommandLine()
{
   bool rval = AppPlugin::didParseCommandLine();

   // process flags
   // only done after bootstrap mode so that all modules info is available
   if(rval && getApp()->getMode() != App::BOOTSTRAP)
   {
      Config& cfg = getApp()->getMetaConfig()
         ["options"][PLUGIN_CL_CFG_ID][ConfigManager::MERGE][PLUGIN_NAME];

      if(cfg["printModuleVersions"]->getBoolean())
      {
         // FIXME: print out module info
         /*
         printf("%s v%s\n", ...);
         // Raise known exit exception.
         ExceptionRef e = new Exception(
            "Module versions printed.",
            "monarch.app.Exit", EXIT_SUCCESS);
         Exception::set(e);
         rval = false;
         */
         ExceptionRef e = new Exception(
            "Not implemented.",
            "monarch.app.NotImplemented", EXIT_FAILURE);
         Exception::set(e);
         rval = false;
      }
   }

   return rval;
}

bool KernelPlugin::runApp()
{
   bool rval = true;

   mState = Starting;
   while(mState == Starting || mState == Restarting)
   {
      // [re]start the node
      MO_CAT_INFO(MO_KERNEL_CAT,
         (mState == Restarting) ?
            "Restarting kernel..." : "Starting kernel...");

      // get kernel config
      Config cfg = getApp()->getConfig()[PLUGIN_NAME];
      App* app = new App;

      // create and start kernel
      mKernel = new MicroKernel();
      mKernel->setConfigManager(app->getConfigManager(), false);
      mKernel->setFiberScheduler(new FiberScheduler(), true);
      mKernel->setFiberMessageCenter(new FiberMessageCenter(), true);
      mKernel->setEventController(new EventController(), true);
      mKernel->setEventDaemon(new EventDaemon(), true);
      mKernel->setServer(new Server(), true);

      // set thread and connection limits
      mKernel->setMaxAuxiliaryThreads(cfg["maxThreadCount"]->getUInt32());
      mKernel->setMaxServerConnections(cfg["maxConnectionCount"]->getUInt32());

      rval = mKernel->start();
      if(rval)
      {
         rval =
            mKernel->loadModule(
               createMonarchPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createConfigPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createLoggingPluginFactory, freeAppPluginFactory) &&
            mKernel->loadModule(
               createKernelPluginFactory, freeAppPluginFactory);

         // FIXME: in did load configs should add env paths to config

         // Collect all module paths so they can be loaded in bulk.
         // This helps to avoid issues with needing to specify load order
         // explicitly.
         FileList modulePaths;
         ConfigIterator mpMods = cfg["modulePath"].getIterator();
         while(rval && mpMods->hasNext())
         {
            ConfigIterator mpPaths = mpMods->next().getIterator();
            while(rval && mpPaths->hasNext())
            {
               const char* path = mpPaths->next()->getString();
               FileList pathList = File::parsePath(path);
               modulePaths->concat(*pathList);
            }
         }
         // load all module paths at once
         rval = mKernel->loadModules(modulePaths);

         if(!rval)
         {
            MO_CAT_INFO(MO_KERNEL_CAT, "Stopping kernel due to exception.");
            mKernel->stop();
         }
      }
      mState = Running;

      if(rval)
      {
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel started.");

         // send ready event
         {
            Event e;
            e["type"] = "monarch.kernel.Kernel.ready";
            mKernel->getEventController()->schedule(e);
         }

         if(rval)
         {
            {
               // create AppPlugins from all loaded AppPluginFactories
               MicroKernel::ModuleApiList factories;
               mKernel->getModuleApisByType(
                  "monarch.app.AppPluginFactory", factories);
               for(MicroKernel::ModuleApiList::iterator i = factories.begin();
                  rval && i != factories.end(); i++)
               {
                  ModuleId id = dynamic_cast<Module*>(*i)->getId();
                  AppPluginFactory* f = dynamic_cast<AppPluginFactory*>(*i);
                  AppPluginRef p = f->createAppPlugin();
                  MO_CAT_OBJECT_INFO(
                     MO_KERNEL_CAT, app,
                     "Adding AppPlugin to App: %s v%s.", id.name, id.version);
                  rval = app->addPlugin(p);
               }
            }

            // waiter for kernel and plugin events
            // used to wait for plugins to complete or for kernel control events
            EventWaiter waiter(mKernel->getEventController());
            // wait for generic kernel events
            waiter.start("monarch.kernel.Kernel.shutdown");
            waiter.start("monarch.kernel.Kernel.restart");

            // collect event counts and start waiting for them
            // make a map of event ids to a counter
            DynamicObject waitEvents;
            waitEvents->setType(Map);
            // get the event config
            {
               // map of arrays of event ids
               Config cfgWaitEvents =
                  getApp()->getConfig()[PLUGIN_NAME]["waitEvents"];
               DynamicObjectIterator i = cfgWaitEvents.getIterator();
               while(i->hasNext())
               {
                  DynamicObjectIterator ii = i->next().getIterator();
                  while(ii->hasNext())
                  {
                     const char* type = i->next()->getString();
                     uint32_t count = 1;
                     if(waitEvents->hasMember(type))
                     {
                        count += waitEvents[type]->getUInt32();
                     }
                     waitEvents[type] = count;
                     // first time seeing event, start waiting for it
                     if(count == 1)
                     {
                        waiter.start(type);
                     }
                  }
               }
            }

            int status;
            if(rval)
            {
               // run sub app
               status = app->start(getApp()->getCommandLine());
               rval = (status == EXIT_SUCCESS);
            }

            // wait for events if app started successfully
            // checking for exception in case of success with an exit exception
            if(rval && !Exception::isSet())
            {
               while(mState == Running && waitEvents->length() != 0)
               {
                  waiter.waitForEvent();
                  Event e = waiter.popEvent();
                  const char* type = e["type"]->getString();
                  MO_CAT_INFO(MO_KERNEL_CAT,
                     "EventWaiter got event: %s", type);
                  if(strcmp("monarch.kernel.Kernel.shutdown", type) == 0)
                  {
                     mState = Stopping;
                  }
                  else if(strcmp("monarch.kernel.Kernel.restart", type) == 0)
                  {
                     mState = Restarting;
                  }
                  else
                  {
                     if(waitEvents->hasMember(type))
                     {
                        uint32_t count = waitEvents[type]->getUInt32();
                        count--;
                        if(count == 0)
                        {
                           waitEvents->removeMember(type);
                        }
                        else
                        {
                           waitEvents[type] = count;
                        }
                     }
                  }
               }
               mState = Stopping;
            }

            if(!rval)
            {
               getApp()->setExitStatus(app->getExitStatus());
            }
         }

         delete app;
         app = NULL;

         // FIXME: actually stopping microkernel, not just node
         // stop node
         MO_CAT_INFO(MO_KERNEL_CAT,
            (mState == Restarting) ?
               "Stopping kernel for restart..." :
               "Stopping kernel...");
         mKernel->stop();
         MO_CAT_INFO(MO_KERNEL_CAT, "Kernel stopped.");
         // set to stopped unless restarting
         mState = (mState == Stopping) ? Stopped : mState;
      }
      else
      {
         MO_CAT_ERROR(MO_KERNEL_CAT, "Kernel start failed: %s",
            JsonWriter::writeToString(Exception::getAsDynamicObject()).c_str());
      }

      if(app != NULL)
      {
         delete app;
         app = NULL;
      }

      // clean up kernel
      delete mKernel;
      mKernel = NULL;
   }

   return rval;
}

bool KernelPlugin::run()
{
   bool rval = AppPlugin::run();
   if(rval && getApp()->getMode() == App::BOOTSTRAP)
   {
      rval = runApp();
   }
   return rval;
}

class KernelPluginFactory :
   public AppPluginFactory
{
public:
   KernelPluginFactory() :
      AppPluginFactory(PLUGIN_NAME, "1.0")
   {
      addDependency("monarch.app.Config", "1.0");
      addDependency("monarch.app.Logging", "1.0");
   }

   virtual ~KernelPluginFactory() {}

   virtual AppPluginRef createAppPlugin()
   {
      return new KernelPlugin();
   }
};

Module* monarch::app::createKernelPluginFactory()
{
   return new KernelPluginFactory();
}
<|endoftext|>


<commit_before>/** \file   Subfields.cc
 *  \brief  Implementation of the Subfields class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2014 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Subfields.h"
#include <stdexcept>
#include "Compiler.h"
#include "util.h"

Subfields::Subfields(const std::string &field_data) {
    if (field_data.size() < 3) {
        indicator1_ = indicator2_ = '\0';
        return;
    }

    std::string::const_iterator ch(field_data.begin());
    indicator1_ = *ch++;
    indicator2_ = *ch++;

    while (ch != field_data.end()) {
        if (*ch != '\x1F')
            std::runtime_error(
                    "in Subfields::Subfields(const std::string &): expected subfield code delimiter not found! "
                            "Found " + std::string(1, *ch) + " in " + field_data + " indicators: "
                    + std::string(1, indicator1_) + ", " + std::string(1, indicator2_) + "! " + field_data);

        ++ch;
        if (ch == field_data.end())
            std::runtime_error(
                    "in Subfields::Subfields(const std::string &): unexpected subfield data end while expecting "
                            "a subfield code! " + field_data);
        const char subfield_code = *ch++;

        std::string subfield_data;
        while (ch != field_data.end() and *ch != '\x1F')
            subfield_data += *ch++;
        if (not subfield_data.empty())
            subfields_.emplace_back(subfield_code, subfield_data);
    }

    std::sort(begin(), end(), SubfieldCodeLessThan());
}

bool Subfields::hasSubfieldWithValue(const char subfield_code, const std::string &value) const {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    for (/* empty */; code_and_value != end() && code_and_value->code_ == subfield_code; ++code_and_value) {
        if (code_and_value->value_ == value)
            return true;
    }
    return false;
}

std::string Subfields::getFirstSubfieldValue(const char subfield_code) const {
    const auto begin_end(getIterators(subfield_code));
    if (begin_end.first == begin_end.second)
        return "";
    return begin_end.first->value_;
}

void Subfields::addSubfield(const char subfield_code, const std::string &subfield_data) {
    auto insert(begin());
    for (/* empty */; insert != end() && insert->code_ <= subfield_code; ++insert);
    subfields_.emplace(insert, subfield_code, subfield_data);
}

void Subfields::replace(const char subfield_code, const std::string &old_value, const std::string &new_value) {
    bool found(false);

    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value) {
        if (code_and_value->value_ == old_value) {
            found = true;
            code_and_value->value_ = new_value;
        }
    }

    if (not found)
        throw std::runtime_error(
                "Subfields::replace: tried to replace \"" + old_value + "\" with \"" + new_value + "\" in subfield '"
                + subfield_code + "' but did not find the original value!");
}

void Subfields::erase(const char subfield_code) {
    const auto begin_end(getIterators(subfield_code));
    subfields_.erase(begin_end.first, begin_end.second);
}

void Subfields::erase(const char subfield_code, const std::string &value) {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    while (code_and_value != end() and code_and_value->code_ == subfield_code) {
        if (code_and_value->value_ == value)
            code_and_value = subfields_.erase(code_and_value);
        else
            ++code_and_value;
    }
}

void Subfields::moveSubfield(const char from_subfield_code, const char to_subfield_code) {
    erase(to_subfield_code);
    std::vector <std::string> values;
    extractSubfields(from_subfield_code, &values);
    for (auto value : values)
        subfields_.emplace_back(to_subfield_code, value);
    erase(from_subfield_code);
    std::sort(begin(), end(), SubfieldCodeLessThan());
}

size_t Subfields::extractSubfields(const std::string &subfield_codes,
                                   std::vector <std::string> *const subfield_values) const {
    for (char subfield_code : subfield_codes) {
        extractSubfields(subfield_code, subfield_values);
    }
    return subfield_values->size();
}

void Subfields::extractSubfields(const char subfield_code, std::vector <std::string> *const subfield_values) const {
    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value)
        subfield_values->emplace_back(code_and_value->value_);
}

std::string Subfields::toString() const {
    std::string as_string;

    as_string += indicator1_;
    as_string += indicator2_;

    for (const_iterator code_and_value(cbegin()); code_and_value != cend(); ++code_and_value) {
        as_string += '\x1F';
        as_string += code_and_value->code_;
        as_string += code_and_value->value_;
    }

    return as_string;
}
<commit_msg>Cosmetic.<commit_after>/** \file   Subfields.cc
 *  \brief  Implementation of the Subfields class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2014,2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Subfields.h"
#include <stdexcept>
#include "Compiler.h"
#include "util.h"

Subfields::Subfields(const std::string &field_data) {
    if (field_data.size() < 3) {
        indicator1_ = indicator2_ = '\0';
        return;
    }

    std::string::const_iterator ch(field_data.begin());
    indicator1_ = *ch++;
    indicator2_ = *ch++;

    while (ch != field_data.end()) {
        if (*ch != '\x1F')
            std::runtime_error(
                "in Subfields::Subfields(const std::string &): expected subfield code delimiter not found! "
                "Found " + std::string(1, *ch) + " in " + field_data + " indicators: "
                + std::string(1, indicator1_) + ", " + std::string(1, indicator2_) + "! " + field_data);

        ++ch;
        if (ch == field_data.end())
            std::runtime_error(
                "in Subfields::Subfields(const std::string &): unexpected subfield data end while expecting "
                "a subfield code! " + field_data);
        const char subfield_code(*ch++);

        std::string subfield_data;
        while (ch != field_data.end() and *ch != '\x1F')
            subfield_data += *ch++;
        if (not subfield_data.empty())
            subfields_.emplace_back(subfield_code, subfield_data);
    }

    std::sort(begin(), end(), SubfieldCodeLessThan());
}

bool Subfields::hasSubfieldWithValue(const char subfield_code, const std::string &value) const {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    for (/* empty */; code_and_value != end() && code_and_value->code_ == subfield_code; ++code_and_value) {
        if (code_and_value->value_ == value)
            return true;
    }
    return false;
}

std::string Subfields::getFirstSubfieldValue(const char subfield_code) const {
    const auto begin_end(getIterators(subfield_code));
    if (begin_end.first == begin_end.second)
        return "";
    return begin_end.first->value_;
}

void Subfields::addSubfield(const char subfield_code, const std::string &subfield_data) {
    auto insert(begin());
    for (/* empty */; insert != end() && insert->code_ <= subfield_code; ++insert);
    subfields_.emplace(insert, subfield_code, subfield_data);
}

void Subfields::replace(const char subfield_code, const std::string &old_value, const std::string &new_value) {
    bool found(false);

    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value) {
        if (code_and_value->value_ == old_value) {
            found = true;
            code_and_value->value_ = new_value;
        }
    }

    if (not found)
        throw std::runtime_error(
                "Subfields::replace: tried to replace \"" + old_value + "\" with \"" + new_value + "\" in subfield '"
                + subfield_code + "' but did not find the original value!");
}

void Subfields::erase(const char subfield_code) {
    const auto begin_end(getIterators(subfield_code));
    subfields_.erase(begin_end.first, begin_end.second);
}

void Subfields::erase(const char subfield_code, const std::string &value) {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    while (code_and_value != end() and code_and_value->code_ == subfield_code) {
        if (code_and_value->value_ == value)
            code_and_value = subfields_.erase(code_and_value);
        else
            ++code_and_value;
    }
}

void Subfields::moveSubfield(const char from_subfield_code, const char to_subfield_code) {
    erase(to_subfield_code);
    std::vector <std::string> values;
    extractSubfields(from_subfield_code, &values);
    for (auto value : values)
        subfields_.emplace_back(to_subfield_code, value);
    erase(from_subfield_code);
    std::sort(begin(), end(), SubfieldCodeLessThan());
}

size_t Subfields::extractSubfields(const std::string &subfield_codes,
                                   std::vector <std::string> *const subfield_values) const {
    for (char subfield_code : subfield_codes) {
        extractSubfields(subfield_code, subfield_values);
    }
    return subfield_values->size();
}

void Subfields::extractSubfields(const char subfield_code, std::vector <std::string> *const subfield_values) const {
    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value)
        subfield_values->emplace_back(code_and_value->value_);
}

std::string Subfields::toString() const {
    std::string as_string;

    as_string += indicator1_;
    as_string += indicator2_;

    for (const_iterator code_and_value(cbegin()); code_and_value != cend(); ++code_and_value) {
        as_string += '\x1F';
        as_string += code_and_value->code_;
        as_string += code_and_value->value_;
    }

    return as_string;
}
<|endoftext|>


<commit_before>#include "game/gamestate.h"
#include "game/city/city.h"

#include "framework/includes.h"
#include "framework/framework.h"

namespace OpenApoc {

GameState::GameState(Framework &fw, Rules &rules)
{
	for (auto &orgdef : rules.getOrganisationDefs())
	{
		this->organisations.emplace_back(orgdef);
	}

	this->city.reset(new City(fw));
	//Place some random testing vehicles
	std::default_random_engine generator;
	//FIXME: Read size from city? (Only 'temporary' code anyway)
	std::uniform_int_distribution<int> xydistribution(0,99);
	// Spawn vehicles at the top to avoid creating them in small
	// inescapeable gaps in buildings
	std::uniform_int_distribution<int> zdistribution(8,9);

	for (int i = 0; i < 50; i++)
	{
		int x = 0;
		int y = 0;
		int z = 0;
		do {
			x = xydistribution(generator);
			y = xydistribution(generator);
			z = zdistribution(generator);
		} while(!this->city->getTile(x,y,z)->ownedObjects.empty());

		auto vehicleDefIt = fw.rules->getVehicleDefs().find("POLICE_HOVERCAR");
		if (vehicleDefIt == fw.rules->getVehicleDefs().end())
		{
			LogError("No POLICE_HOVERCAR vehicle def found?");
			return;
		}
		//Organisations[3] == megapol
		auto testVehicle = std::make_shared<Vehicle>(vehicleDefIt->second, this->organisations[3]);
		this->city->vehicles.push_back(testVehicle);
		testVehicle->launch(*this->city, Vec3<float>{x,y,z});
	}
	for (int i = 0; i < 50; i++)
	{
		int x = 0;
		int y = 0;
		int z = 0;
		do {
			x = xydistribution(generator);
			y = xydistribution(generator);
			z = zdistribution(generator);
		} while(!this->city->getTile(x,y,z)->ownedObjects.empty());

		auto vehicleDefIt = fw.rules->getVehicleDefs().find("PHOENIX_HOVERCAR");
		if (vehicleDefIt == fw.rules->getVehicleDefs().end())
		{
			LogError("No PHOENIX_HOVERCAR vehicle def found?");
			return;
		}
		//Organisations[3] == X-Com
		auto testVehicle = std::make_shared<Vehicle>(vehicleDefIt->second, this->organisations[0]);
		this->city->vehicles.push_back(testVehicle);
		testVehicle->launch(*this->city, Vec3<float>{x,y,z});
	}
}

}; //namespace OpenApoc
<commit_msg>Build fix - #include <random><commit_after>#include "game/gamestate.h"
#include "game/city/city.h"

#include "framework/includes.h"
#include "framework/framework.h"

#include <random>

namespace OpenApoc {

GameState::GameState(Framework &fw, Rules &rules)
{
	for (auto &orgdef : rules.getOrganisationDefs())
	{
		this->organisations.emplace_back(orgdef);
	}

	this->city.reset(new City(fw));
	//Place some random testing vehicles
	std::default_random_engine generator;
	//FIXME: Read size from city? (Only 'temporary' code anyway)
	std::uniform_int_distribution<int> xydistribution(0,99);
	// Spawn vehicles at the top to avoid creating them in small
	// inescapeable gaps in buildings
	std::uniform_int_distribution<int> zdistribution(8,9);

	for (int i = 0; i < 50; i++)
	{
		int x = 0;
		int y = 0;
		int z = 0;
		do {
			x = xydistribution(generator);
			y = xydistribution(generator);
			z = zdistribution(generator);
		} while(!this->city->getTile(x,y,z)->ownedObjects.empty());

		auto vehicleDefIt = fw.rules->getVehicleDefs().find("POLICE_HOVERCAR");
		if (vehicleDefIt == fw.rules->getVehicleDefs().end())
		{
			LogError("No POLICE_HOVERCAR vehicle def found?");
			return;
		}
		//Organisations[3] == megapol
		auto testVehicle = std::make_shared<Vehicle>(vehicleDefIt->second, this->organisations[3]);
		this->city->vehicles.push_back(testVehicle);
		testVehicle->launch(*this->city, Vec3<float>{x,y,z});
	}
	for (int i = 0; i < 50; i++)
	{
		int x = 0;
		int y = 0;
		int z = 0;
		do {
			x = xydistribution(generator);
			y = xydistribution(generator);
			z = zdistribution(generator);
		} while(!this->city->getTile(x,y,z)->ownedObjects.empty());

		auto vehicleDefIt = fw.rules->getVehicleDefs().find("PHOENIX_HOVERCAR");
		if (vehicleDefIt == fw.rules->getVehicleDefs().end())
		{
			LogError("No PHOENIX_HOVERCAR vehicle def found?");
			return;
		}
		//Organisations[3] == X-Com
		auto testVehicle = std::make_shared<Vehicle>(vehicleDefIt->second, this->organisations[0]);
		this->city->vehicles.push_back(testVehicle);
		testVehicle->launch(*this->city, Vec3<float>{x,y,z});
	}
}

}; //namespace OpenApoc
<|endoftext|>


<commit_before>#ifndef MESSAGES_HPP_
#define MESSAGES_HPP_

#include <cstdint>

namespace protocol {
namespace message {

struct heartbeat_message_t {
  static const int ID = 0xFE; // TODO: Probably make this 0x00

  std::uint8_t seq;
} __attribute__((packed));

std::uint16_t length(int id) {
  // TODO(kyle): sizeof(empty struct) is 1 in C++...
  switch(id) {
    case heartbeat_message_t::ID:
      return sizeof(heartbeat_message_t);
  }

  return 0; // TODO(kyle): Return something more meaningful?
}

}
}

#endif // MESSAGES_HPP_

<commit_msg>Use enum for message ID to avoid linking errors.<commit_after>#ifndef MESSAGES_HPP_
#define MESSAGES_HPP_

#include <cstdint>

namespace protocol {
namespace message {

struct heartbeat_message_t {
  enum { ID = 0xFE };

  std::uint8_t seq;
} __attribute__((packed));

std::uint16_t length(int id) {
  // TODO(kyle): sizeof(empty struct) is 1 in C++...
  switch(id) {
    case heartbeat_message_t::ID:
      return sizeof(heartbeat_message_t);
  }

  return 0; // TODO(kyle): Return something more meaningful?
}

}
}

#endif // MESSAGES_HPP_

<|endoftext|>


<commit_before>#include <SFML/Graphics.hpp>
#include <iostream>
#include "sfJoystick.h"
#include "sfMouse.h"
#include "sfKeyboard.h"
#include "sfSpriteSheet.h"
#include "GameComponent.h"
#include "Stage.h"
#include "Skin.h"

#ifdef WIN32
#include <boost\asio.hpp>
#include <Windows.h>
#endif

extern	std::vector<skin>	skinArray;
extern	sfWindow	sfmlWin;

int main()
{
	fillArray();
	ISpriteSheet	*test = new sfSpriteSheet(skinArray[0].filePath, skinArray[0].anim, skinArray[0].frame);
	ISpriteSheet	*test2 = new sfSpriteSheet(skinArray[8].filePath, skinArray[8].anim, skinArray[8].frame);
	ISpriteSheet	*ships = new sfSpriteSheet("../Resources/Sprite/ennemy_bullet1.gif", 1, 8);
	ISpriteSheet	*boom = new sfSpriteSheet(skinArray[7].filePath, skinArray[7].anim, skinArray[7].frame);
	ISpriteSheet	*boom2 = new sfSpriteSheet("../Resources/Sprite/big_death.gif", 1, 8);
	ISpriteSheet	*bing = new sfSpriteSheet(skinArray[9].filePath, skinArray[9].anim, skinArray[9].frame);
	ISpriteSheet	*ennemy = new sfSpriteSheet("../Resources/Sprite/ennemy1.gif", 1, 8);

<<<<<<< HEAD
	//IInput	*input3 = new sfKeyboard();
=======

	IInput	*input3 = new sfKeyboard();
>>>>>>> 317e185242f0b1773191a19a6c54679e66905c46
	//IInput	*input2 = new sfJoystick();
	IInput	*input = new sfMouse();

	/*
	input3->autoBind(UpKey, sf::Keyboard::W);
	input3->autoBind(DownKey, sf::Keyboard::S);
	input3->autoBind(LeftKey, sf::Keyboard::A);
	input3->autoBind(RightKey, sf::Keyboard::D);
	input3->autoBind(FireKey, sf::Keyboard::Space);
	*/

	GameComponent	*vaisseau = new GameComponent(test, boom);
	GameComponent	*vaisseau2 = new GameComponent(test2, boom2);
	Stage st;
	st.add(vaisseau);
	st.add(vaisseau2);

	int	i = 0, o = 1;
	vaisseau2->move(5, 0);
	//balise copiage de code
	sf::Event ev;
	while (sfmlWin.isOpen())
	{
		sfmlWin.pollEvent(ev);
		if (ev.type == sf::Event::Closed)
			sfmlWin.getWindow().close();
		Sleep(10); //TODO replace par truc utiles genre les packets udp lol
		int x = 0, y = 0;
		vaisseau->move(input->getLastInput(UpKey), input->getLastInput(LeftKey));
		//vaisseau->move(input2->getLastInput(UpKey), input2->getLastInput(LeftKey));
		/*if (input3->getLastInput(UpKey))
			y = -4;
		else if (input3->getLastInput(DownKey))
			y = 4;
		if (input3->getLastInput(LeftKey))
			x = -4;
		else if (input3->getLastInput(RightKey))
			x = 4;
		vaisseau->move(x, y);
		if (input3->isPressed(FireKey))
			vaisseau->death();
		*/
		st.update();
		sfmlWin.clear();
		st.draw();
		sfmlWin.display();
	}
	//balise fin copiage de code
	return 0;
}
/*
#include	<iostream>
#include	"NetworkManager.hpp"

int		main(int ac, char **av)
{
  if (ac == 3)
    {
      INetworkManager*	NM = new NetworkManager(av);
      NM->run();
    }
  else
    std::cout << "Usage : ./ClientRtype [ip] [port]" << std::endl;
}
*/<commit_msg>[Clean] Bug merge corrected<commit_after>#include <SFML/Graphics.hpp>
#include <iostream>
#include "sfJoystick.h"
#include "sfMouse.h"
#include "sfKeyboard.h"
#include "sfSpriteSheet.h"
#include "GameComponent.h"
#include "Stage.h"
#include "Skin.h"

#ifdef WIN32
#include <boost\asio.hpp>
#include <Windows.h>
#endif

extern	std::vector<skin>	skinArray;
extern	sfWindow	sfmlWin;

int main()
{
	fillArray();
	ISpriteSheet	*test = new sfSpriteSheet(skinArray[0].filePath, skinArray[0].anim, skinArray[0].frame);
	ISpriteSheet	*test2 = new sfSpriteSheet(skinArray[8].filePath, skinArray[8].anim, skinArray[8].frame);
	ISpriteSheet	*ships = new sfSpriteSheet("../Resources/Sprite/ennemy_bullet1.gif", 1, 8);
	ISpriteSheet	*boom = new sfSpriteSheet(skinArray[7].filePath, skinArray[7].anim, skinArray[7].frame);
	ISpriteSheet	*boom2 = new sfSpriteSheet("../Resources/Sprite/big_death.gif", 1, 8);
	ISpriteSheet	*bing = new sfSpriteSheet(skinArray[9].filePath, skinArray[9].anim, skinArray[9].frame);
	ISpriteSheet	*ennemy = new sfSpriteSheet("../Resources/Sprite/ennemy1.gif", 1, 8);

	//IInput	*input3 = new sfKeyboard();
	//IInput	*input2 = new sfJoystick();
	IInput	*input = new sfMouse();

	/*
	input3->autoBind(UpKey, sf::Keyboard::W);
	input3->autoBind(DownKey, sf::Keyboard::S);
	input3->autoBind(LeftKey, sf::Keyboard::A);
	input3->autoBind(RightKey, sf::Keyboard::D);
	input3->autoBind(FireKey, sf::Keyboard::Space);
	*/

	GameComponent	*vaisseau = new GameComponent(test, boom);
	GameComponent	*vaisseau2 = new GameComponent(test2, boom2);
	Stage st;
	st.add(vaisseau);
	st.add(vaisseau2);

	int	i = 0, o = 1;
	vaisseau2->move(5, 0);
	//balise copiage de code
	sf::Event ev;
	while (sfmlWin.isOpen())
	{
		sfmlWin.pollEvent(ev);
		if (ev.type == sf::Event::Closed)
			sfmlWin.getWindow().close();
		Sleep(10); //TODO replace par truc utiles genre les packets udp lol
		int x = 0, y = 0;
		vaisseau->move(input->getLastInput(UpKey), input->getLastInput(LeftKey));
		//vaisseau->move(input2->getLastInput(UpKey), input2->getLastInput(LeftKey));
		/*if (input3->getLastInput(UpKey))
			y = -4;
		else if (input3->getLastInput(DownKey))
			y = 4;
		if (input3->getLastInput(LeftKey))
			x = -4;
		else if (input3->getLastInput(RightKey))
			x = 4;
		vaisseau->move(x, y);
		if (input3->isPressed(FireKey))
			vaisseau->death();
		*/
		st.update();
		sfmlWin.clear();
		st.draw();
		sfmlWin.display();
	}
	//balise fin copiage de code
	return 0;
}
/*
#include	<iostream>
#include	"NetworkManager.hpp"

int		main(int ac, char **av)
{
  if (ac == 3)
    {
      INetworkManager*	NM = new NetworkManager(av);
      NM->run();
    }
  else
    std::cout << "Usage : ./ClientRtype [ip] [port]" << std::endl;
}
*/<|endoftext|>


<commit_before>//
//  macros.hpp
//
//  Created By Davis Blalock on 3/15/16.
//  Copyright (c) 2016 Davis Blalock. All rights reserved.
//

#ifndef __MACROS_HPP
#define __MACROS_HPP

// ------------------------ restrict keyword
// adapted from http://stackoverflow.com/a/5948101/1153180

#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
	#define RESTRICT __restrict__

	#define LIKELY(x)    __builtin_expect (!!(x), 1)
	#define UNLIKELY(x)  __builtin_expect (!!(x), 0)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)
#elif defined(__clang__)
	#define RESTRICT __restrict__

	#define LIKELY(x)    __builtin_expect (!!(x), 1)
	#define UNLIKELY(x)  __builtin_expect (!!(x), 0)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)
#else
	#if defined(_MSC_VER) && _MSC_VER >= 1400
		#define RESTRICT
	#else
		#define RESTRICT __restrict
	#endif

	#define LIKELY(x)    (x)
	#define UNLIKELY(x)  (x)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)

#endif

// count the number of arguments in a varargs list
#define VA_NUM_ARGS(...) _VA_NUM_ARGS_IMPL(__VA_ARGS__, \
	16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define _VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
	 _13, _14, _15, _16, N, ...) N

#ifdef __cplusplus
// ------------------------ type traits macros
	#include <type_traits>

	// #define SELF_TYPE \
	// 	typename std::remove_reference<decltype(*this)>::type

	// put these in function bodies to statically assert that appropriate types
	// have been passed in as template params; prefer using the below type
	// constraint macros, however
	#define ASSERT_TRAIT(TRAIT, T, MSG) static_assert(std::TRAIT<T>::value, MSG)
	#define ASSERT_INTEGRAL(T) ASSERT_TRAIT(is_integral, T, "Type not integral!")

	// put these as extra template params to enforce constraints
	// on previous template params; e.g.:
	//
	// template<class T, REQUIRE_INT(T)> T foo(T arg) { return arg + 1; }
	//

	// ------------------------ require that some constexpr be true

	#define REQ(EXPR) \
		typename = typename std::enable_if<EXPR, void>::type

	// have to wrap EXPR in a local template param for enable_if to work on
	// a class method where EXPR is a class template param
	#define _METHOD_REQ(EXPR, NAME) \
		bool NAME = EXPR, typename = typename std::enable_if<NAME, void>::type

	#define METHOD_REQ0(EXPR) \
		_METHOD_REQ(EXPR, __expr0__)

	#define METHOD_REQ1(EXPR) \
		_METHOD_REQ(EXPR, __expr1__)

	#define METHOD_REQ2(EXPR) \
		_METHOD_REQ(EXPR, __expr2__)

	#define METHOD_REQ3(EXPR) \
		_METHOD_REQ3(EXPR, __expr3__)

	#define METHOD_REQ4(EXPR) \
		_METHOD_REQ(EXPR, __expr4__)

	#define METHOD_REQ5(EXPR) \
		_METHOD_REQ(EXPR, __expr5__)

	#define METHOD_REQ6(EXPR) \
		_METHOD_REQ(EXPR, __expr6__)

	#define METHOD_REQ(EXPR) \
		_METHOD_REQ(EXPR, __expr__)

		// bool __expr__ = EXPR, typename = typename std::enable_if<__expr__, void>::type

		// typename = typename std::enable_if<EXPR, T>::type
	#define REQUIRE_TRAIT(TRAIT, T) \
		typename = typename std::enable_if<std::TRAIT<T>::value, T>::type

	#define REQUIRE_NOT_TRAIT(TRAIT, T) \
		typename = typename std::enable_if<!std::TRAIT<T>::value, T>::type

	#define REQUIRE_IS_A(BASE, T) \
		typename = typename std::enable_if<std::is_base_of<BASE, T>::value, T>::type

	#define REQUIRE_IS_NOT_A(BASE, T) \
		typename = typename std::enable_if<!std::is_base_of<BASE, T>::value, T>::type

		// REQ(!std::is_base_of<BASE, T>::value)

	#define REQUIRE_INT(T) REQUIRE_TRAIT(is_integral, T)
	#define REQUIRE_NUM(T) REQUIRE_TRAIT(is_arithmetic, T)
	#define REQUIRE_FLOAT(T) REQUIRE_TRAIT(is_floating_point, T)
	#define REQUIRE_PRIMITIVE(T) REQUIRE_TRAIT(is_arithmetic, T)
	#define REQUIRE_NOT_PTR(T) REQUIRE_NOT_TRAIT(is_pointer, T)

	#define REQ_HAS_ATTR(T, METHOD_INVOCATION) \
		typename=decltype(std::declval<T>() . METHOD_INVOCATION)

	// ------------------------ is_valid; requires C++14
	// inspired by https://gist.github.com/Jiwan/7a586c739a30dd90d259

	template <typename T> struct _valid_helper {
	private:
	    template <typename Param> constexpr auto _is_valid(int _)
		    // type returned by decltype is last type in the list (here,
			// std::true_type), but previous types must be valid
	    	-> decltype(std::declval<T>()(std::declval<Param>()),
	    		std::true_type())
	    {
	        return std::true_type();
	    }

	    template <typename Param> constexpr std::false_type _is_valid(...) {
	        return std::false_type();
	    }

	public:
	    template <typename Param> constexpr auto operator()(const Param& p) {
	        return _is_valid<Param>(int(0));
	    }
	};

	template <typename T> constexpr auto is_valid(const T& t) {
	    return _valid_helper<T>();
	}

	#define CREATE_TEST(OBJNAME, EXPR) \
		is_valid([](auto&& OBJNAME) -> decltype(EXPR) { })

	#define CREATE_TEST_X(EXPR) \
		is_valid([](auto&& x) -> decltype(EXPR) { })

	#define TEST_FOR_METHOD(INVOCATION) \
		is_valid([](auto&& x) -> decltype(x. INVOCATION) { })

	#define PASSES_TEST(OBJ, TEST) \
		decltype(TEST(OBJ))::value

	#define TYPE_PASSES_TEST(T, TEST) \
		PASSES_TEST(std::declval<T>(), TEST)

	#define REQ_TYPE_PASSES(T, TEST) \
		REQ(TYPE_PASSES_TEST(T, TEST))

	#define ENABLE_IF(EXPR, T) \
		typename std::enable_if<EXPR, T>::type

// ------------------------ TYPES(...) convenience macro for template args
#define TYPES_1(A) template<typename A>
#define TYPES_2(A, B) \
	template<typename A, typename B>
#define TYPES_3(A, B, C) \
	template<typename A, typename B, typename C>
		// TYPES_10(A, B, C, D, E, F=int, G=int, H=int, I=int, J=int)
#define TYPES_4(A, B, C, D) \
	template<typename A, typename B, typename C, typename D>
		// TYPES_10(A, B, C, D, E=int, F=int, G=int, H=int, I=int, J=int)
#define TYPES_5(A, B, C, D, E) \
	template<typename A, typename B, typename C, typename D, typename E>
		// TYPES_10(A, B, C, D, E, F=int, G=int, H=int, I=int, J=int)
#define TYPES_6(A, B, C, D, E, F) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F>
		// TYPES_10(A, B, C, D, E, F, G=int, H=int, I=int, J=int)
#define TYPES_7(A, B, C, D, E, F, G) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G>
		// TYPES_10(A, B, C, D, E, F, G, H=int, I=int, J=int)
#define TYPES_8(A, B, C, D, E, F, G, H) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H>
		// TYPES_10(A, B, C, D, E, F, G, H, I=int, J=int)
#define TYPES_9(A, B, C, D, E, F, G, H, I) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H, typename I>
		// TYPES_10(A, B, C, D, E, F, G, H, I, J=int)
#define TYPES_10(A, B, C, D, E, F, G, H, I, J) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H, typename I, typename J

// define a top level TYPES macro that automatically calls the macro with
// the proper number of arguments
// #define _TYPES_IMPL2(count, ...) TYPES_ ## count (__VA_ARGS__)
// #define _TYPES_IMPL(count, ...) _TYPES_IMPL2(count, __VA_ARGS__)
// #define TYPES(...) _TYPES_IMPL(VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

// TODO if this works, get rid of above 3 loc and move outside of cpp block
#define _WRAP_VARIADIC_IMPL2(name, count, ...) \
		name ## count (__VA_ARGS__)
#define _WRAP_VARIADIC_IMPL(name, count, ...) \
		_WRAP_VARIADIC_IMPL2(name, count, __VA_ARGS__)
#define WRAP_VARIADIC(name, ...) \
		_WRAP_VARIADIC_IMPL(name, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

#define TYPES(...) WRAP_VARIADIC(TYPES, __VA_ARGS__)

// #undef _TYPES_IMPL
// #undef _TYPES_IMPL2
#undef _WRAP_VARIADIC_IMPL
#undef _WRAP_VARIADIC_IMPL2
#undef VA_NUM_ARGS
#undef _VA_NUM_ARGS_IMPL

// ------------------------ static size assertions from Eigen

#define _PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
    ( \
        (int(TYPE0::SizeAtCompileTime)==0 && int(TYPE1::SizeAtCompileTime)==0) \
    || (\
          (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE0::RowsAtCompileTime)==int(TYPE1::RowsAtCompileTime)) \
      &&  (int(TYPE0::ColsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE1::ColsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE0::ColsAtCompileTime)==int(TYPE1::ColsAtCompileTime))\
       ) \
    )

#define STATIC_ASSERT_SAME_SHAPE(TYPE0,TYPE1) \
	static_assert(_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1), \
		YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)

#undef _PREDICATE_SAME_MATRIX_SIZE

#define PRINT_STATIC_TYPE(X) \
	static_assert(decltype(X)::__debug__, #X);

#endif // __cplusplus

#endif // __MACROS_HPP
<commit_msg>add optional<> to macros file + fix type in prefetch_rw macro<commit_after>//
//  macros.hpp
//
//  Created By Davis Blalock on 3/15/16.
//  Copyright (c) 2016 Davis Blalock. All rights reserved.
//

#ifndef __MACROS_HPP
#define __MACROS_HPP

// ------------------------ restrict keyword
// adapted from http://stackoverflow.com/a/5948101/1153180

#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
	#define RESTRICT __restrict__

	#define LIKELY(x)    __builtin_expect (!!(x), 1)
	#define UNLIKELY(x)  __builtin_expect (!!(x), 0)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)
#elif defined(__clang__)
	#define RESTRICT __restrict__

	#define LIKELY(x)    __builtin_expect (!!(x), 1)
	#define UNLIKELY(x)  __builtin_expect (!!(x), 0)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 0, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT) \
		__builtin_prefetch(ADDR, 1, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)
#else
	#if defined(_MSC_VER) && _MSC_VER >= 1400
		#define RESTRICT
	#else
		#define RESTRICT __restrict
	#endif

	#define LIKELY(x)    (x)
	#define UNLIKELY(x)  (x)

	#define PREFETCH_WITH_STICKINESS(ADDR, INT)
	#define PREFETCH_RW_WITH_STICKINESS(ADDR, INT)
	#define PREFETCH_TRANSIENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_PERSISTENT(ADDR) PREFETCH_WITH_STICKINESS(ADDR, 3)
	#define PREFETCH_RW_TRANSIENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 0)
	#define PREFETCH_RW_PERSISTENT(ADDR) PREFETCH_RW_WITH_STICKINESS(ADDR, 3)

#endif

// count the number of arguments in a varargs list
#define VA_NUM_ARGS(...) _VA_NUM_ARGS_IMPL(__VA_ARGS__, \
	16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define _VA_NUM_ARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
	 _13, _14, _15, _16, N, ...) N

#ifdef __cplusplus
// ------------------------ type aliases // TODO macros file not ideal place
	#include <experimental/optional>
	// will be std::optional in c++17
	template<class T> using optional = std::experimental::optional<T>;
	static constexpr auto nullopt = std::experimental::nullopt;

// ------------------------ type traits macros
	#include <type_traits>

	// #define SELF_TYPE \
	// 	typename std::remove_reference<decltype(*this)>::type

	// put these in function bodies to statically assert that appropriate types
	// have been passed in as template params; prefer using the below type
	// constraint macros, however
	#define ASSERT_TRAIT(TRAIT, T, MSG) static_assert(std::TRAIT<T>::value, MSG)
	#define ASSERT_INTEGRAL(T) ASSERT_TRAIT(is_integral, T, "Type not integral!")

	// put these as extra template params to enforce constraints
	// on previous template params; e.g.:
	//
	// template<class T, REQUIRE_INT(T)> T foo(T arg) { return arg + 1; }
	//

	// ------------------------ require that some constexpr be true

	#define REQ(EXPR) \
		typename = typename std::enable_if<EXPR, void>::type

	// have to wrap EXPR in a local template param for enable_if to work on
	// a class method where EXPR is a class template param
	#define _METHOD_REQ(EXPR, NAME) \
		bool NAME = EXPR, typename = typename std::enable_if<NAME, void>::type

	#define METHOD_REQ0(EXPR) \
		_METHOD_REQ(EXPR, __expr0__)

	#define METHOD_REQ1(EXPR) \
		_METHOD_REQ(EXPR, __expr1__)

	#define METHOD_REQ2(EXPR) \
		_METHOD_REQ(EXPR, __expr2__)

	#define METHOD_REQ3(EXPR) \
		_METHOD_REQ3(EXPR, __expr3__)

	#define METHOD_REQ4(EXPR) \
		_METHOD_REQ(EXPR, __expr4__)

	#define METHOD_REQ5(EXPR) \
		_METHOD_REQ(EXPR, __expr5__)

	#define METHOD_REQ6(EXPR) \
		_METHOD_REQ(EXPR, __expr6__)

	#define METHOD_REQ(EXPR) \
		_METHOD_REQ(EXPR, __expr__)

		// bool __expr__ = EXPR, typename = typename std::enable_if<__expr__, void>::type

		// typename = typename std::enable_if<EXPR, T>::type
	#define REQUIRE_TRAIT(TRAIT, T) \
		typename = typename std::enable_if<std::TRAIT<T>::value, T>::type

	#define REQUIRE_NOT_TRAIT(TRAIT, T) \
		typename = typename std::enable_if<!std::TRAIT<T>::value, T>::type

	#define REQUIRE_IS_A(BASE, T) \
		typename = typename std::enable_if<std::is_base_of<BASE, T>::value, T>::type

	#define REQUIRE_IS_NOT_A(BASE, T) \
		typename = typename std::enable_if<!std::is_base_of<BASE, T>::value, T>::type

		// REQ(!std::is_base_of<BASE, T>::value)

	#define REQUIRE_INT(T) REQUIRE_TRAIT(is_integral, T)
	#define REQUIRE_NUM(T) REQUIRE_TRAIT(is_arithmetic, T)
	#define REQUIRE_FLOAT(T) REQUIRE_TRAIT(is_floating_point, T)
	#define REQUIRE_PRIMITIVE(T) REQUIRE_TRAIT(is_arithmetic, T)
	#define REQUIRE_NOT_PTR(T) REQUIRE_NOT_TRAIT(is_pointer, T)

	#define REQ_HAS_ATTR(T, METHOD_INVOCATION) \
		typename=decltype(std::declval<T>() . METHOD_INVOCATION)

	// ------------------------ is_valid; requires C++14
	// inspired by https://gist.github.com/Jiwan/7a586c739a30dd90d259

	template <typename T> struct _valid_helper {
	private:
	    template <typename Param> constexpr auto _is_valid(int _)
		    // type returned by decltype is last type in the list (here,
			// std::true_type), but previous types must be valid
	    	-> decltype(std::declval<T>()(std::declval<Param>()),
	    		std::true_type())
	    {
	        return std::true_type();
	    }

	    template <typename Param> constexpr std::false_type _is_valid(...) {
	        return std::false_type();
	    }

	public:
	    template <typename Param> constexpr auto operator()(const Param& p) {
	        return _is_valid<Param>(int(0));
	    }
	};

	template <typename T> constexpr auto is_valid(const T& t) {
	    return _valid_helper<T>();
	}

	#define CREATE_TEST(OBJNAME, EXPR) \
		is_valid([](auto&& OBJNAME) -> decltype(EXPR) { })

	#define CREATE_TEST_X(EXPR) \
		is_valid([](auto&& x) -> decltype(EXPR) { })

	#define TEST_FOR_METHOD(INVOCATION) \
		is_valid([](auto&& x) -> decltype(x. INVOCATION) { })

	#define PASSES_TEST(OBJ, TEST) \
		decltype(TEST(OBJ))::value

	#define TYPE_PASSES_TEST(T, TEST) \
		PASSES_TEST(std::declval<T>(), TEST)

	#define REQ_TYPE_PASSES(T, TEST) \
		REQ(TYPE_PASSES_TEST(T, TEST))

	#define ENABLE_IF(EXPR, T) \
		typename std::enable_if<EXPR, T>::type

// ------------------------ TYPES(...) convenience macro for template args
#define TYPES_1(A) template<typename A>
#define TYPES_2(A, B) \
	template<typename A, typename B>
#define TYPES_3(A, B, C) \
	template<typename A, typename B, typename C>
		// TYPES_10(A, B, C, D, E, F=int, G=int, H=int, I=int, J=int)
#define TYPES_4(A, B, C, D) \
	template<typename A, typename B, typename C, typename D>
		// TYPES_10(A, B, C, D, E=int, F=int, G=int, H=int, I=int, J=int)
#define TYPES_5(A, B, C, D, E) \
	template<typename A, typename B, typename C, typename D, typename E>
		// TYPES_10(A, B, C, D, E, F=int, G=int, H=int, I=int, J=int)
#define TYPES_6(A, B, C, D, E, F) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F>
		// TYPES_10(A, B, C, D, E, F, G=int, H=int, I=int, J=int)
#define TYPES_7(A, B, C, D, E, F, G) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G>
		// TYPES_10(A, B, C, D, E, F, G, H=int, I=int, J=int)
#define TYPES_8(A, B, C, D, E, F, G, H) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H>
		// TYPES_10(A, B, C, D, E, F, G, H, I=int, J=int)
#define TYPES_9(A, B, C, D, E, F, G, H, I) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H, typename I>
		// TYPES_10(A, B, C, D, E, F, G, H, I, J=int)
#define TYPES_10(A, B, C, D, E, F, G, H, I, J) \
	template<typename A, typename B, typename C, typename D, typename E, \
		typename F, typename G, typename H, typename I, typename J

// define a top level TYPES macro that automatically calls the macro with
// the proper number of arguments
// #define _TYPES_IMPL2(count, ...) TYPES_ ## count (__VA_ARGS__)
// #define _TYPES_IMPL(count, ...) _TYPES_IMPL2(count, __VA_ARGS__)
// #define TYPES(...) _TYPES_IMPL(VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

// TODO if this works, get rid of above 3 loc and move outside of cpp block
#define _WRAP_VARIADIC_IMPL2(name, count, ...) \
		name ## count (__VA_ARGS__)
#define _WRAP_VARIADIC_IMPL(name, count, ...) \
		_WRAP_VARIADIC_IMPL2(name, count, __VA_ARGS__)
#define WRAP_VARIADIC(name, ...) \
		_WRAP_VARIADIC_IMPL(name, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

#define TYPES(...) WRAP_VARIADIC(TYPES, __VA_ARGS__)

// #undef _TYPES_IMPL
// #undef _TYPES_IMPL2
#undef _WRAP_VARIADIC_IMPL
#undef _WRAP_VARIADIC_IMPL2
#undef VA_NUM_ARGS
#undef _VA_NUM_ARGS_IMPL

// ------------------------ static size assertions from Eigen

#define _PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1) \
    ( \
        (int(TYPE0::SizeAtCompileTime)==0 && int(TYPE1::SizeAtCompileTime)==0) \
    || (\
          (int(TYPE0::RowsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE1::RowsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE0::RowsAtCompileTime)==int(TYPE1::RowsAtCompileTime)) \
      &&  (int(TYPE0::ColsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE1::ColsAtCompileTime)==Eigen::Dynamic \
        || int(TYPE0::ColsAtCompileTime)==int(TYPE1::ColsAtCompileTime))\
       ) \
    )

#define STATIC_ASSERT_SAME_SHAPE(TYPE0,TYPE1) \
	static_assert(_PREDICATE_SAME_MATRIX_SIZE(TYPE0,TYPE1), \
		YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)

#undef _PREDICATE_SAME_MATRIX_SIZE

#define PRINT_STATIC_TYPE(X) \
	static_assert(decltype(X)::__debug__, #X);

#endif // __cplusplus

#endif // __MACROS_HPP
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 <stdlib.h>
#include "Transcoder.hpp"

XERCES_CPP_NAMESPACE_USE

static bool DEBUG_IN = false;
static bool DEBUG_OUT = false;

Transcoder* Transcoder::_instance = NULL;

Transcoder*
Transcoder::getInstance() {
  // fprintf(stderr, "getInstance: finding instance\n");
  if (_instance == NULL) {
    // fprintf(stderr, "getInstance: making new transcoder\n");
    _instance = new Transcoder();
  }
  return _instance;
}

Transcoder::~Transcoder() {
  // fprintf(stderr, "Deleting transcoder\n");
}

Transcoder::Transcoder() {
  XMLTransService::Codes failReason;

  // we assume that the Xerces-C transcoding service is already initialized
  // via XMLPlatformUtils::Initialize()
  UTF8_TRANSCODER = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(
						XMLUni::fgUTF8EncodingString,
						failReason,
						1024);

  if (UTF8_TRANSCODER == NULL) {
    croak("ERROR: Transcoder Could not create UTF-8 transcoder");
  } else if (failReason == XMLTransService::UnsupportedEncoding) {
    croak("ERROR: Transcoder: unsupported encoding");
  } else if (failReason == XMLTransService::InternalFailure) {
    croak("ERROR: Transcoder: internal failure");
  } else if (failReason == XMLTransService::SupportFilesNotFound) {
    croak("ERROR: Transcoder: support files not found");
  } else if (failReason == XMLTransService::Ok) {
    // fprintf(stderr, "Created transcoder ok\n");
  }
}

SV*
Transcoder::XMLString2Local(const XMLCh* input) {
  if (input == NULL) {
    return &PL_sv_undef;
  }

  SV *output;
  unsigned int charsEaten = 0;
  int length  = XMLString::stringLen(input);            // string length
  // use +1 to make room for the '\0' at the end of the string
  // in the pathological case when each character of the string
  // is UTF8_MAXLEN bytes long
  XMLByte* res = new XMLByte[(length * UTF8_MAXLEN) + 1]; // output string

  unsigned int total_chars =
    UTF8_TRANSCODER->transcodeTo((const XMLCh*) input,
				   (unsigned int) length,
				   (XMLByte*) res,
				   (unsigned int) (length*UTF8_MAXLEN),
				   charsEaten,
				   XMLTranscoder::UnRep_Throw
				   );
  res[total_chars] = '\0';

#if (0)
  if (DEBUG_OUT) {
      printf("Xerces out length = %d: ",total_chars);
      for (int i=0;i<length;i++){
	  printf("<0x%.4X>",res[i]);
      }
      printf("\n");
  }
#endif

  output = sv_newmortal();
  sv_setpv((SV*)output, (char *)res );
  SvUTF8_on((SV*)output);
  delete[] res;
  return output;
}

XMLCh*
Transcoder::Local2XMLString(SV* input){

    if (input == &PL_sv_undef) {
      return NULL;
    }

    XMLCh* output;

    STRLEN length;
    char *ptr = (char *)SvPVutf8(input,length);

#if (0)
    if (DEBUG_IN) {
	printf("Perl in length = %d: ",length);
	for (unsigned int i=0;i<length;i++){
	    printf("<0x%.4X>",ptr[i]);
	}
	printf("\n");
    }
#endif

    if (SvUTF8(input)) {
	unsigned int charsEaten = 0;
        unsigned char* sizes = new unsigned char[length+1];
        output = new XMLCh[length+1];
	unsigned int chars_stored =
	    UTF8_TRANSCODER->transcodeFrom((const XMLByte*) ptr,
					   (unsigned int) length,
					   (XMLCh*) output,
					   (unsigned int) length,
					   charsEaten,
					   (unsigned char*)sizes
					   );
	delete [] sizes;

#if (0)
	if (DEBUG_IN) {
	    printf("Xerces in length = %d: ",chars_stored);
	    for (unsigned int i=0;i<chars_stored;i++){
		printf("<0x%.4X>",output[i]);
	    }
	    printf("\n");
	}
#endif

	// indicate the end of the string
	output[chars_stored] = '\0';
    } else {
	output = XMLString::transcode(ptr);

#if (0)
	if (DEBUG_IN) {
	    printf("Xerces: ");
	    for (int i=0;output[i];i++){
		printf("<0x%.4X>",output[i]);
	    }
	    printf("\n");
	}
#endif

    }
    return(output);
}

<commit_msg>64 bit compile issues: unsigned int -> XMLSize_t<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 <stdlib.h>
#include "Transcoder.hpp"

XERCES_CPP_NAMESPACE_USE

static bool DEBUG_IN = false;
static bool DEBUG_OUT = false;

Transcoder* Transcoder::_instance = NULL;

Transcoder*
Transcoder::getInstance() {
  // fprintf(stderr, "getInstance: finding instance\n");
  if (_instance == NULL) {
    // fprintf(stderr, "getInstance: making new transcoder\n");
    _instance = new Transcoder();
  }
  return _instance;
}

Transcoder::~Transcoder() {
  // fprintf(stderr, "Deleting transcoder\n");
}

Transcoder::Transcoder() {
  XMLTransService::Codes failReason;

  // we assume that the Xerces-C transcoding service is already initialized
  // via XMLPlatformUtils::Initialize()
  UTF8_TRANSCODER = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(
						XMLUni::fgUTF8EncodingString,
						failReason,
						1024);

  if (UTF8_TRANSCODER == NULL) {
    croak("ERROR: Transcoder Could not create UTF-8 transcoder");
  } else if (failReason == XMLTransService::UnsupportedEncoding) {
    croak("ERROR: Transcoder: unsupported encoding");
  } else if (failReason == XMLTransService::InternalFailure) {
    croak("ERROR: Transcoder: internal failure");
  } else if (failReason == XMLTransService::SupportFilesNotFound) {
    croak("ERROR: Transcoder: support files not found");
  } else if (failReason == XMLTransService::Ok) {
    // fprintf(stderr, "Created transcoder ok\n");
  }
}

SV*
Transcoder::XMLString2Local(const XMLCh* input) {
  if (input == NULL) {
    return &PL_sv_undef;
  }

  SV *output;
  XMLSize_t charsEaten = 0;
  int length  = XMLString::stringLen(input);            // string length
  // use +1 to make room for the '\0' at the end of the string
  // in the pathological case when each character of the string
  // is UTF8_MAXLEN bytes long
  XMLByte* res = new XMLByte[(length * UTF8_MAXLEN) + 1]; // output string

  XMLSize_t total_chars =
    UTF8_TRANSCODER->transcodeTo((const XMLCh*) input,
				   (XMLSize_t) length,
				   (XMLByte*) res,
				   (XMLSize_t) (length*UTF8_MAXLEN),
				   charsEaten,
				   XMLTranscoder::UnRep_Throw
				   );
  res[total_chars] = '\0';

#if (0)
  if (DEBUG_OUT) {
      printf("Xerces out length = %d: ",total_chars);
      for (int i=0;i<length;i++){
	  printf("<0x%.4X>",res[i]);
      }
      printf("\n");
  }
#endif

  output = sv_newmortal();
  sv_setpv((SV*)output, (char *)res );
  SvUTF8_on((SV*)output);
  delete[] res;
  return output;
}

XMLCh*
Transcoder::Local2XMLString(SV* input){

    if (input == &PL_sv_undef) {
      return NULL;
    }

    XMLCh* output;

    STRLEN length;
    char *ptr = (char *)SvPVutf8(input,length);

#if (0)
    if (DEBUG_IN) {
	printf("Perl in length = %d: ",length);
	for (unsigned int i=0;i<length;i++){
	    printf("<0x%.4X>",ptr[i]);
	}
	printf("\n");
    }
#endif

    if (SvUTF8(input)) {
	XMLSize_t charsEaten = 0;
        unsigned char* sizes = new unsigned char[length+1];
        output = new XMLCh[length+1];
	XMLSize_t chars_stored =
	    UTF8_TRANSCODER->transcodeFrom((const XMLByte*) ptr,
					   (XMLSize_t) length,
					   (XMLCh*) output,
					   (XMLSize_t) length,
					   charsEaten,
					   (unsigned char*)sizes
					   );
	delete [] sizes;

#if (0)
	if (DEBUG_IN) {
	    printf("Xerces in length = %d: ",chars_stored);
	    for (unsigned int i=0;i<chars_stored;i++){
		printf("<0x%.4X>",output[i]);
	    }
	    printf("\n");
	}
#endif

	// indicate the end of the string
	output[chars_stored] = '\0';
    } else {
	output = XMLString::transcode(ptr);

#if (0)
	if (DEBUG_IN) {
	    printf("Xerces: ");
	    for (int i=0;output[i];i++){
		printf("<0x%.4X>",output[i]);
	    }
	    printf("\n");
	}
#endif

    }
    return(output);
}

<|endoftext|>


<commit_before>//=============================================================================
//
//                               OpenMesh
//      Copyright (C) 2001-2003 by Computer Graphics Group, RWTH Aachen
//                           www.openmesh.org
//
//-----------------------------------------------------------------------------
//
//                                License
//
//   This library is free software; you can redistribute it and/or modify it
//   under the terms of the GNU Lesser General Public License as published
//   by the Free Software Foundation, version 2.1.
//
//   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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
//   $Revision$
//   $Date$
//
//=============================================================================

//=============================================================================
//
//  CLASS StripifierT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_STRIPIFIERT_C

//== INCLUDES =================================================================

#include <OpenMesh/Tools/Utils/StripifierT.hh>
#include <list>

//== NAMESPACES ===============================================================

namespace OpenMesh {

  //== IMPLEMENTATION ==========================================================

template <class Mesh>
StripifierT<Mesh>::
StripifierT(Mesh& _mesh) :
    mesh_(_mesh)
{
  // preprocess:  add new properties
  mesh_.add_property( processed_ );
  mesh_.add_property( used_ );
  mesh_.request_face_status();
}

template <class Mesh>
StripifierT<Mesh>::
~StripifierT() {
  // postprocess:  remove properties
  mesh_.remove_property(processed_);
  mesh_.remove_property(used_);
  mesh_.release_face_status();
}

template <class Mesh>
unsigned int
StripifierT<Mesh>::
stripify()
{
  // build strips
  clear();
  build_strips();

  return n_strips();
}

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

template <class Mesh>
void
StripifierT<Mesh>::
build_strips()
{
  Strip                           experiments[3];
  typename Mesh::HalfedgeHandle   h[3];
  unsigned int                    best_idx, best_length, length;
  FaceHandles                     faces[3];
  typename FaceHandles::iterator  fh_it, fh_end;
  typename Mesh::FaceIter         f_it, f_end=mesh_.faces_end();

  // init faces to be un-processed and un-used
  // deleted or hidden faces are marked processed
  if (mesh_.has_face_status())
  {
    for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
      if (mesh_.status(f_it).hidden() || mesh_.status(f_it).deleted())
        processed(f_it) = used(f_it) = true;
      else
        processed(f_it) = used(f_it) = false;
  }
  else
  {
    for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
      processed(f_it) = used(f_it) = false;
  }

  for (f_it=mesh_.faces_begin(); true; )
  {
    // find start face
    for (; f_it!=f_end; ++f_it)
      if (!processed(f_it))
        break;
    if (f_it==f_end) break; // stop if all have been processed

    // collect starting halfedges
    h[0] = mesh_.halfedge_handle(f_it.handle());
    h[1] = mesh_.next_halfedge_handle(h[0]);
    h[2] = mesh_.next_halfedge_handle(h[1]);

    // build 3 strips, take best one
    best_length = best_idx = 0;
    for (unsigned int i=0; i<3; ++i)
    {
      build_strip(h[i], experiments[i], faces[i]);
      if ((length = experiments[i].size()) > best_length)
      {
        best_length = length;
        best_idx    = i;
      }

      for (fh_it=faces[i].begin(), fh_end=faces[i].end();
           fh_it!=fh_end; ++fh_it)
        used(*fh_it) = false;
    }

    // update processed status
    fh_it  = faces[best_idx].begin();
    fh_end = faces[best_idx].end();
    for (; fh_it!=fh_end; ++fh_it)
      processed(*fh_it) = true;

    // add best strip to strip-list
    strips_.push_back(experiments[best_idx]);
  }
}

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

template <class Mesh>
void
StripifierT<Mesh>::
build_strip(typename Mesh::HalfedgeHandle _start_hh,
            Strip& _strip,
            FaceHandles& _faces)
{
  std::list<unsigned int>  strip;
  typename Mesh::HalfedgeHandle   hh;
  typename Mesh::FaceHandle       fh;

  // reset face list
  _faces.clear();

  // init strip
  strip.push_back(mesh_.from_vertex_handle(_start_hh).idx());
  strip.push_back(mesh_.to_vertex_handle(_start_hh).idx());

  // walk along the strip: 1st direction
  hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh));
  while (1)
  {
    // go right
    hh = mesh_.next_halfedge_handle(hh);
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_back(mesh_.to_vertex_handle(hh).idx());

    // go left
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_back(mesh_.to_vertex_handle(hh).idx());
  }

  // walk along the strip: 2nd direction
  bool flip(false);
  hh = mesh_.prev_halfedge_handle(_start_hh);
  while (1)
  {
    // go right
    hh = mesh_.next_halfedge_handle(hh);
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_front(mesh_.to_vertex_handle(hh).idx());
    flip = true;

    // go left
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_front(mesh_.to_vertex_handle(hh).idx());
    flip = false;
  }

  if (flip) strip.push_front(strip.front());

  // copy final strip to _strip
  _strip.clear();
  _strip.reserve(strip.size());
  std::copy(strip.begin(), strip.end(), std::back_inserter(_strip));
}

//=============================================================================
} // namespace OpenMesh
  //=============================================================================
<commit_msg>Revert last patch<commit_after>//=============================================================================
//
//                               OpenMesh
//      Copyright (C) 2001-2003 by Computer Graphics Group, RWTH Aachen
//                           www.openmesh.org
//
//-----------------------------------------------------------------------------
//
//                                License
//
//   This library is free software; you can redistribute it and/or modify it
//   under the terms of the GNU Lesser General Public License as published
//   by the Free Software Foundation, version 2.1.
//
//   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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
//   $Revision$
//   $Date$
//
//=============================================================================

//=============================================================================
//
//  CLASS StripifierT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_STRIPIFIERT_C

//== INCLUDES =================================================================

#include <OpenMesh/Tools/Utils/StripifierT.hh>
#include <list>

//== NAMESPACES ===============================================================

namespace OpenMesh {

  //== IMPLEMENTATION ==========================================================

template <class Mesh>
StripifierT<Mesh>::
StripifierT(Mesh& _mesh) :
    mesh_(_mesh)
{

}

template <class Mesh>
StripifierT<Mesh>::
~StripifierT() {

}

template <class Mesh>
unsigned int
StripifierT<Mesh>::
stripify()
{
  // preprocess:  add new properties
  mesh_.add_property( processed_ );
  mesh_.add_property( used_ );
  mesh_.request_face_status();

  // build strips
  clear();
  build_strips();

  // postprocess:  remove properties
  mesh_.remove_property(processed_);
  mesh_.remove_property(used_);
  mesh_.release_face_status();

  return n_strips();
}

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

template <class Mesh>
void
StripifierT<Mesh>::
build_strips()
{
  Strip                           experiments[3];
  typename Mesh::HalfedgeHandle   h[3];
  unsigned int                    best_idx, best_length, length;
  FaceHandles                     faces[3];
  typename FaceHandles::iterator  fh_it, fh_end;
  typename Mesh::FaceIter         f_it, f_end=mesh_.faces_end();

  // init faces to be un-processed and un-used
  // deleted or hidden faces are marked processed
  if (mesh_.has_face_status())
  {
    for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
      if (mesh_.status(f_it).hidden() || mesh_.status(f_it).deleted())
        processed(f_it) = used(f_it) = true;
      else
        processed(f_it) = used(f_it) = false;
  }
  else
  {
    for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
      processed(f_it) = used(f_it) = false;
  }

  for (f_it=mesh_.faces_begin(); true; )
  {
    // find start face
    for (; f_it!=f_end; ++f_it)
      if (!processed(f_it))
        break;
    if (f_it==f_end) break; // stop if all have been processed

    // collect starting halfedges
    h[0] = mesh_.halfedge_handle(f_it.handle());
    h[1] = mesh_.next_halfedge_handle(h[0]);
    h[2] = mesh_.next_halfedge_handle(h[1]);

    // build 3 strips, take best one
    best_length = best_idx = 0;
    for (unsigned int i=0; i<3; ++i)
    {
      build_strip(h[i], experiments[i], faces[i]);
      if ((length = experiments[i].size()) > best_length)
      {
        best_length = length;
        best_idx    = i;
      }

      for (fh_it=faces[i].begin(), fh_end=faces[i].end();
           fh_it!=fh_end; ++fh_it)
        used(*fh_it) = false;
    }

    // update processed status
    fh_it  = faces[best_idx].begin();
    fh_end = faces[best_idx].end();
    for (; fh_it!=fh_end; ++fh_it)
      processed(*fh_it) = true;

    // add best strip to strip-list
    strips_.push_back(experiments[best_idx]);
  }
}

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

template <class Mesh>
void
StripifierT<Mesh>::
build_strip(typename Mesh::HalfedgeHandle _start_hh,
            Strip& _strip,
            FaceHandles& _faces)
{
  std::list<unsigned int>  strip;
  typename Mesh::HalfedgeHandle   hh;
  typename Mesh::FaceHandle       fh;

  // reset face list
  _faces.clear();

  // init strip
  strip.push_back(mesh_.from_vertex_handle(_start_hh).idx());
  strip.push_back(mesh_.to_vertex_handle(_start_hh).idx());

  // walk along the strip: 1st direction
  hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh));
  while (1)
  {
    // go right
    hh = mesh_.next_halfedge_handle(hh);
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_back(mesh_.to_vertex_handle(hh).idx());

    // go left
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_back(mesh_.to_vertex_handle(hh).idx());
  }

  // walk along the strip: 2nd direction
  bool flip(false);
  hh = mesh_.prev_halfedge_handle(_start_hh);
  while (1)
  {
    // go right
    hh = mesh_.next_halfedge_handle(hh);
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_front(mesh_.to_vertex_handle(hh).idx());
    flip = true;

    // go left
    hh = mesh_.opposite_halfedge_handle(hh);
    hh = mesh_.next_halfedge_handle(hh);
    if (mesh_.is_boundary(hh)) break;
    fh = mesh_.face_handle(hh);
    if (processed(fh) || used(fh)) break;
    _faces.push_back(fh);
    used(fh) = true;
    strip.push_front(mesh_.to_vertex_handle(hh).idx());
    flip = false;
  }

  if (flip) strip.push_front(strip.front());

  // copy final strip to _strip
  _strip.clear();
  _strip.reserve(strip.size());
  std::copy(strip.begin(), strip.end(), std::back_inserter(_strip));
}

//=============================================================================
} // namespace OpenMesh
  //=============================================================================
<|endoftext|>