<commit_before>//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat Feb 14 21:40:14 PST 2015
// Last Modified: Sat Feb 14 23:33:51 PST 2015
// Filename:      midifile/src/MidiEvent.cpp
// Website:       http://midifile.sapp.org
// Syntax:        C++11
// vim:           ts=3 expandtab
//
// Description:   A class which stores a MidiMessage and a timestamp
//                for the MidiFile class.
//

#include "MidiEvent.h"
#include <stdlib.h>

using namespace std;

//////////////////////////////
//
// MidiEvent::MidiEvent -- Constructor classes
//

MidiEvent::MidiEvent(void) : MidiMessage() {
   clearVariables();
}

MidiEvent::MidiEvent(int command) : MidiMessage(command)  {
   clearVariables();
}

MidiEvent::MidiEvent(int command, int p1) : MidiMessage(command, p1) {
   clearVariables();
}

MidiEvent::MidiEvent(int command, int p1, int p2)
      : MidiMessage(command, p1, p2) {
   clearVariables();
}

MidiEvent::MidiEvent(int aTime, int aTrack, vector<uchar>& message)
      : MidiMessage(message) {
   tick  = aTime;
   track = aTrack;
   eventlink = NULL;
}

MidiEvent::MidiEvent(const MidiEvent& mfevent) {
   tick  = mfevent.tick;
   track = mfevent.track;
   eventlink = NULL;
   this->resize(mfevent.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = mfevent[i];
   }
}

//////////////////////////////
//
// MidiEvent::~MidiEvent -- MidiFile Event destructor
//

MidiEvent::~MidiEvent() {
   tick  = -1;
   track = -1;
   this->resize(0);
   eventlink = NULL;
}

//////////////////////////////
//
// MidiEvent::clearVariables --  Clear everything except MidiMessage data.
//

void MidiEvent::clearVariables(void) {
   tick  = 0;
   track = 0;
   seconds = 0.0;
   eventlink = NULL;
}

//////////////////////////////
//
// MidiEvent::operator= -- Copy the contents of another MidiEvent.
//

MidiEvent& MidiEvent::operator=(MidiEvent& mfevent) {
   if (this == &mfevent) {
      return *this;
   }
   tick  = mfevent.tick;
   track = mfevent.track;
   eventlink = NULL;
   this->resize(mfevent.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = mfevent[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(MidiMessage& message) {
   if (this == &message) {
      return *this;
   }
   clearVariables();
   this->resize(message.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = message[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<uchar>& bytes) {
   clearVariables();
   this->resize(bytes.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = bytes[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<char>& bytes) {
   clearVariables();
   setMessage(bytes);
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<int>& bytes) {
   clearVariables();
   setMessage(bytes);
   return *this;
}

//////////////////////////////
//
// MidiEvent::unlinkEvent -- Disassociate this event with another.
//   Also tell the other event to disassociate from this event.
//

void MidiEvent::unlinkEvent(void) {
   if (eventlink == NULL) {
      return;
   }
   MidiEvent* mev = eventlink;
   eventlink = NULL;
   mev->unlinkEvent();
}

//////////////////////////////
//
// MidiEvent::linkEvent -- Make a link between two messages.
//   Unlinking
//

void MidiEvent::linkEvent(MidiEvent* mev) {
   if (mev->eventlink != NULL) {
      // unlink other event if it is linked to something else;
      mev->unlinkEvent();
   }
   // if this is already linked to something else, then unlink:
   if (eventlink != NULL) {
      eventlink->unlinkEvent();
   }
   unlinkEvent();

   mev->eventlink = this;
   eventlink = mev;
}

void MidiEvent::linkEvent(MidiEvent& mev) {
   linkEvent(&mev);
}

//////////////////////////////
//
// MidiEvent::getLinkedEvent -- Returns a linked event.  Usually
//   this is the note-off message for a note-on message and vice-versa.
//   Returns null if there are no links.
//

MidiEvent* MidiEvent::getLinkedEvent(void) {
   return eventlink;
}

//////////////////////////////
//
// MidiEvent::isLinked -- Returns true if there is an event which is not
//   NULL.  This function is similar to getLinkedEvent().
//

int MidiEvent::isLinked(void) {
   return eventlink == NULL ? 0 : 1;
}

//////////////////////////////
//
// MidiEvent::getTickDuration --  For linked events (note-ons and note-offs),
//    return the absolute tick time difference between the two events.
//    The tick values are presumed to be in absolute tick mode rather than
//    delta tick mode.  Returns 0 if not linked.
//

int MidiEvent::getTickDuration(void) {
   MidiEvent* mev = getLinkedEvent();
   if (mev == NULL) {
      return 0;
   }
   int tick2 = mev->tick;
   if (tick2 > tick) {
      return tick2 - tick;
   } else {
      return tick - tick2;
   }
}

//////////////////////////////
//
// MidiEvent::getDurationInSeconds -- For linked events (note-ons and
//     note-offs), return the duration of the note in seconds.  The
//     seconds analysis must be done first; otherwise the duration will be
//     reported as zero.
//

double MidiEvent::getDurationInSeconds(void) {
   MidiEvent* mev = getLinkedEvent();
   if (mev == NULL) {
      return 0;
   }
   double seconds2 = mev->seconds;
   if (seconds2 > seconds) {
      return seconds2 - seconds;
   } else {
      return seconds - seconds2;
   }
}

<commit_msg>Fix MidiEvent copy constructor<commit_after>//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat Feb 14 21:40:14 PST 2015
// Last Modified: Sat Feb 14 23:33:51 PST 2015
// Filename:      midifile/src/MidiEvent.cpp
// Website:       http://midifile.sapp.org
// Syntax:        C++11
// vim:           ts=3 expandtab
//
// Description:   A class which stores a MidiMessage and a timestamp
//                for the MidiFile class.
//

#include "MidiEvent.h"
#include <stdlib.h>

using namespace std;

//////////////////////////////
//
// MidiEvent::MidiEvent -- Constructor classes
//

MidiEvent::MidiEvent(void) : MidiMessage() {
   clearVariables();
}

MidiEvent::MidiEvent(int command) : MidiMessage(command)  {
   clearVariables();
}

MidiEvent::MidiEvent(int command, int p1) : MidiMessage(command, p1) {
   clearVariables();
}

MidiEvent::MidiEvent(int command, int p1, int p2)
      : MidiMessage(command, p1, p2) {
   clearVariables();
}

MidiEvent::MidiEvent(int aTime, int aTrack, vector<uchar>& message)
      : MidiMessage(message) {
   tick  = aTime;
   track = aTrack;
   eventlink = NULL;
}

MidiEvent::MidiEvent(const MidiEvent& mfevent) {
   tick  = mfevent.tick;
   track = mfevent.track;
   seconds = mfevent.seconds;
   eventlink = NULL;
   this->resize(mfevent.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = mfevent[i];
   }
}

//////////////////////////////
//
// MidiEvent::~MidiEvent -- MidiFile Event destructor
//

MidiEvent::~MidiEvent() {
   tick  = -1;
   track = -1;
   this->resize(0);
   eventlink = NULL;
}

//////////////////////////////
//
// MidiEvent::clearVariables --  Clear everything except MidiMessage data.
//

void MidiEvent::clearVariables(void) {
   tick  = 0;
   track = 0;
   seconds = 0.0;
   eventlink = NULL;
}

//////////////////////////////
//
// MidiEvent::operator= -- Copy the contents of another MidiEvent.
//

MidiEvent& MidiEvent::operator=(MidiEvent& mfevent) {
   if (this == &mfevent) {
      return *this;
   }
   tick  = mfevent.tick;
   track = mfevent.track;
   seconds = mfevent.seconds;
   eventlink = NULL;
   this->resize(mfevent.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = mfevent[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(MidiMessage& message) {
   if (this == &message) {
      return *this;
   }
   clearVariables();
   this->resize(message.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = message[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<uchar>& bytes) {
   clearVariables();
   this->resize(bytes.size());
   for (int i=0; i<this->size(); i++) {
      (*this)[i] = bytes[i];
   }
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<char>& bytes) {
   clearVariables();
   setMessage(bytes);
   return *this;
}

MidiEvent& MidiEvent::operator=(vector<int>& bytes) {
   clearVariables();
   setMessage(bytes);
   return *this;
}

//////////////////////////////
//
// MidiEvent::unlinkEvent -- Disassociate this event with another.
//   Also tell the other event to disassociate from this event.
//

void MidiEvent::unlinkEvent(void) {
   if (eventlink == NULL) {
      return;
   }
   MidiEvent* mev = eventlink;
   eventlink = NULL;
   mev->unlinkEvent();
}

//////////////////////////////
//
// MidiEvent::linkEvent -- Make a link between two messages.
//   Unlinking
//

void MidiEvent::linkEvent(MidiEvent* mev) {
   if (mev->eventlink != NULL) {
      // unlink other event if it is linked to something else;
      mev->unlinkEvent();
   }
   // if this is already linked to something else, then unlink:
   if (eventlink != NULL) {
      eventlink->unlinkEvent();
   }
   unlinkEvent();

   mev->eventlink = this;
   eventlink = mev;
}

void MidiEvent::linkEvent(MidiEvent& mev) {
   linkEvent(&mev);
}

//////////////////////////////
//
// MidiEvent::getLinkedEvent -- Returns a linked event.  Usually
//   this is the note-off message for a note-on message and vice-versa.
//   Returns null if there are no links.
//

MidiEvent* MidiEvent::getLinkedEvent(void) {
   return eventlink;
}

//////////////////////////////
//
// MidiEvent::isLinked -- Returns true if there is an event which is not
//   NULL.  This function is similar to getLinkedEvent().
//

int MidiEvent::isLinked(void) {
   return eventlink == NULL ? 0 : 1;
}

//////////////////////////////
//
// MidiEvent::getTickDuration --  For linked events (note-ons and note-offs),
//    return the absolute tick time difference between the two events.
//    The tick values are presumed to be in absolute tick mode rather than
//    delta tick mode.  Returns 0 if not linked.
//

int MidiEvent::getTickDuration(void) {
   MidiEvent* mev = getLinkedEvent();
   if (mev == NULL) {
      return 0;
   }
   int tick2 = mev->tick;
   if (tick2 > tick) {
      return tick2 - tick;
   } else {
      return tick - tick2;
   }
}

//////////////////////////////
//
// MidiEvent::getDurationInSeconds -- For linked events (note-ons and
//     note-offs), return the duration of the note in seconds.  The
//     seconds analysis must be done first; otherwise the duration will be
//     reported as zero.
//

double MidiEvent::getDurationInSeconds(void) {
   MidiEvent* mev = getLinkedEvent();
   if (mev == NULL) {
      return 0;
   }
   double seconds2 = mev->seconds;
   if (seconds2 > seconds) {
      return seconds2 - seconds;
   } else {
      return seconds - seconds2;
   }
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream> // TODO Remove
#include <cmake.h>
#include <algorithm>
#include <stdio.h>
#include <Context.h>
#include <Hooks.h>
#include <text.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());
  }
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       On launch, after data structures are initiliazed, before
//                    data is loaded.
// Data fed to stdin: None
// Exit code:         0: Success, proceed
//                    !0: Failure, terminate
// Output handled:    0:  context.header ()
//                    !0: context.error ()
void Hooks::onLaunch ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       On exit, after processing is complete, before output is
//                    displayed.
// Data fed to stdin: None
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  context.footnote ()
//                    !0: context.error ()
void Hooks::onExit ()
{
  context.timer_hooks.start ();

  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/on-exit") != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
      {
        std::string output;
        int status = execute (*i, "", output);

        std::vector <std::string> lines;
        split (lines, output, '\n');
        std::vector <std::string>::iterator line;

        for (line = lines.begin (); line != lines.end (); ++line)
          if (status == 0)
            context.footnote (*line);
          else
            context.error (*line);
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       A task is created, before it is committed.
// Data fed to stdin: task JSON
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  modified JSON
//                        context.footnote ()
//                    !0: context.error ()
void Hooks::onAdd (Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/on-add") != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
      {
        std::string input = after.composeJSON ();
        std::string output;
        int status = execute (*i, input, output);

        std::vector <std::string> lines;
        split (lines, output, '\n');
        std::vector <std::string>::iterator line;

        if (status == 0)
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.footnote (*line);
        }
        else
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.error (*line);

          throw 0;  // This is how hooks silently terminate processing.
        }
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       A task is modified, before it is committed.
// Data fed to stdin: before JSON
//                    after JSON
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  modified after JSON
//                        context.footnote ()
//                    !0: context.error ()
void Hooks::onModify (const Task& before, Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/on-modify") != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
      {
        std::string afterJSON = after.composeJSON ();
        std::string input = before.composeJSON ()
                          + "\n"
                          + afterJSON;
        std::string output;
        int status = execute (*i, input, output);

        std::vector <std::string> lines;
        split (lines, output, '\n');
        std::vector <std::string>::iterator line;

        if (status == 0)
        {
          after = Task (afterJSON);
          for (line = lines.begin (); line != lines.end (); ++line)
            context.footnote (*line);
        }
        else
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.error (*line);

          throw 0;  // This is how hooks silently terminate processing.
        }
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
int Hooks::execute (
  const std::string& command,
  const std::string& input,
  std::string& output)
{
  int status = -1;
  FILE* fp = popen (command.c_str (), "r+");
  if (fp)
  {
    // Write input to fp.
    if (input != "")
    {
      fputs (input.c_str (), fp);
      fflush (fp);
    }

    // Read output from fp.
    output = "";
    char* line = NULL;
    size_t len = 0;
    while (getline (&line, &len, fp) != -1)
    {
      output += line;
      free (line);
      line = NULL;
    }

    fflush (fp);
    status = pclose (fp);
    context.debug (format ("Hooks::execute {1} (status {2})", command, status));
  }

  return status;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Hooks<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream> // TODO Remove
#include <cmake.h>
#include <algorithm>
#include <stdio.h>
#include <Context.h>
#include <Hooks.h>
#include <text.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
Hooks::Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
Hooks::~Hooks ()
{
}

////////////////////////////////////////////////////////////////////////////////
void Hooks::initialize ()
{
  // Scan <rc.data.location>/hooks
  Directory d (context.config.get ("data.location"));
  d += "hooks";
  if (d.is_directory () &&
      d.readable ())
  {
    _scripts = d.list ();
    std::sort (_scripts.begin (), _scripts.end ());
  }
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       On launch, after data structures are initiliazed, before
//                    data is loaded.
// Data fed to stdin: None
// Exit code:         0: Success, proceed
//                    !0: Failure, terminate
// Output handled:    0:  context.header ()
//                    !0: context.error ()
void Hooks::onLaunch ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-launch");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.header (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);

      throw 0;  // This is how hooks silently terminate processing.
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       On exit, after processing is complete, before output is
//                    displayed.
// Data fed to stdin: None
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  context.footnote ()
//                    !0: context.error ()
void Hooks::onExit ()
{
  context.timer_hooks.start ();

  std::vector <std::string> matchingScripts = scripts ("on-exit");
  std::vector <std::string>::iterator i;
  for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i)
  {
    std::string output;
    int status = execute (*i, "", output);

    std::vector <std::string> lines;
    split (lines, output, '\n');
    std::vector <std::string>::iterator line;

    if (status == 0)
    {
      for (line = lines.begin (); line != lines.end (); ++line)
      {
        if (line->length () && (*line)[0] == '{')
        {
          Task newTask (*line);
          context.tdb2.add (newTask);
        }
        else
          context.footnote (*line);
      }
    }
    else
    {
      for (line = lines.begin (); line != lines.end (); ++line)
        context.error (*line);
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       A task is created, before it is committed.
// Data fed to stdin: task JSON
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  modified JSON
//                        context.footnote ()
//                    !0: context.error ()
void Hooks::onAdd (Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/on-add") != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
      {
        std::string input = after.composeJSON ();
        std::string output;
        int status = execute (*i, input, output);

        std::vector <std::string> lines;
        split (lines, output, '\n');
        std::vector <std::string>::iterator line;

        if (status == 0)
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.footnote (*line);
        }
        else
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.error (*line);

          throw 0;  // This is how hooks silently terminate processing.
        }
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
// Occurs when:       A task is modified, before it is committed.
// Data fed to stdin: before JSON
//                    after JSON
// Exit code:         0: Success
//                    !0: Failure
// Output handled:    0:  modified after JSON
//                        context.footnote ()
//                    !0: context.error ()
void Hooks::onModify (const Task& before, Task& after)
{
  context.timer_hooks.start ();

  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/on-modify") != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
      {
        std::string afterJSON = after.composeJSON ();
        std::string input = before.composeJSON ()
                          + "\n"
                          + afterJSON;
        std::string output;
        int status = execute (*i, input, output);

        std::vector <std::string> lines;
        split (lines, output, '\n');
        std::vector <std::string>::iterator line;

        if (status == 0)
        {
          after = Task (afterJSON);
          for (line = lines.begin (); line != lines.end (); ++line)
            context.footnote (*line);
        }
        else
        {
          for (line = lines.begin (); line != lines.end (); ++line)
            context.error (*line);

          throw 0;  // This is how hooks silently terminate processing.
        }
      }
    }
  }

  context.timer_hooks.stop ();
}

////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Hooks::scripts (const std::string& event)
{
  std::vector <std::string> matching;
  std::vector <std::string>::iterator i;
  for (i = _scripts.begin (); i != _scripts.end (); ++i)
  {
    if (i->find ("/" + event) != std::string::npos)
    {
      File script (*i);
      if (script.executable ())
        matching.push_back (*i);
    }
  }

  return matching;
}

////////////////////////////////////////////////////////////////////////////////
int Hooks::execute (
  const std::string& command,
  const std::string& input,
  std::string& output)
{
  int status = -1;
  FILE* fp = popen (command.c_str (), "r+");
  if (fp)
  {
    // Write input to fp.
    if (input != "")
    {
      fputs (input.c_str (), fp);
      fflush (fp);
    }

    // Read output from fp.
    output = "";
    char* line = NULL;
    size_t len = 0;
    while (getline (&line, &len, fp) != -1)
    {
      output += line;
      free (line);
      line = NULL;
    }

    fflush (fp);
    status = pclose (fp);
    context.debug (format ("Hooks::execute {1} (status {2})", command, status));
  }

  return status;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>/*
 * Image.cpp
 *
 *  Created on: 12 Jun 2014
 *      Author: rick
 */

#include "Image.hpp"

Image::Image(int width, int height) :
        _width(width), _height(height){
    _image.resize(3 * _width * _height);
}

Image::~Image(){
}

void Image::setPixel(int i, int j, float r, float g, float b){
    _image[3 * (_width * j + i)] = r;
    _image[3 * (_width * j + i) + 1] = g;
    _image[3 * (_width * j + i) + 2] = b;
}

void Image::setPixel(int i, int j, Vec3Df rgb){
    _image[3 * (_width * j + i)] = rgb[0];
    _image[3 * (_width * j + i) + 1] = rgb[1];
    _image[3 * (_width * j + i) + 2] = rgb[2];
}

bool Image::writeImage(const char * filename){
    FILE* file;
    file = fopen(filename, "wb");
    if(!file){
        printf("dump file problem... file\n");
        return false;
    }

#ifdef PNG
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t x, y, z;
    png_voidp* row_pointers = NULL;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(png_ptr == NULL){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    info_ptr = png_create_info_struct(png_ptr);
    if(info_ptr == NULL){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    /* Set up error handling. */

    if(setjmp(png_jmpbuf(png_ptr))){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    /* Set image attributes. */

    png_set_IHDR(png_ptr, info_ptr, _width, _height, COLOR_DEPTH,
            PNG_COLOR_TYPE_RGB,
            PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT,
            PNG_FILTER_TYPE_DEFAULT);

    /* Initialize rows of PNG. */

    row_pointers = (png_voidp*)png_malloc(png_ptr,
            _height * sizeof(png_byte *));
    int i = 0;
    for(y = 0;y < _height;++y){
        png_byte *row = (png_byte*)png_malloc(png_ptr,
                sizeof(uint8_t) * _width * PIXEL_SIZE);

        row_pointers[y] = row;
        for(x = 0;x < _width;++x){
            for(z = 0;z < PIXEL_SIZE;z++)
            *row++ = _image[i++] * 255.0f;
        }
    }

    /* Write the image data to "fp". */
    png_init_io(png_ptr, file);
    png_set_rows(png_ptr, info_ptr, (png_bytepp)row_pointers);
    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

    /* The routine has successfully written the file, so we set
     "status" to a value which indicates success. */

    for(y = 0;y < _height;y++){
        png_free(png_ptr, row_pointers[y]);
    }
    png_free(png_ptr, row_pointers);

#else
    fprintf(file, "P6\n%i %i\n255\n", _width, _height);

    std::vector<unsigned char> imageC(_image.size());

    for(unsigned int i = 0;i < _image.size();++i)
        imageC[i] = (unsigned char)(_image[i] * 255.0f);

    int t = fwrite(&(imageC[0]), _width * _height * PIXEL_SIZE, 1, file);
    if(t != 1){
        printf("Dump file problem... fwrite\n");
        return false;
    }
#endif

    fclose(file);
    return true;
}
<commit_msg>added output filename for convenience<commit_after>/*
 * Image.cpp
 *
 *  Created on: 12 Jun 2014
 *      Author: rick
 */

#include "Image.hpp"

Image::Image(int width, int height) :
        _width(width), _height(height){
    _image.resize(3 * _width * _height);
}

Image::~Image(){
}

void Image::setPixel(int i, int j, float r, float g, float b){
    _image[3 * (_width * j + i)] = r;
    _image[3 * (_width * j + i) + 1] = g;
    _image[3 * (_width * j + i) + 2] = b;
}

void Image::setPixel(int i, int j, Vec3Df rgb){
    _image[3 * (_width * j + i)] = rgb[0];
    _image[3 * (_width * j + i) + 1] = rgb[1];
    _image[3 * (_width * j + i) + 2] = rgb[2];
}

bool Image::writeImage(const char * filename){
    FILE* file;
    file = fopen(filename, "wb");
    if(!file){
        printf("dump file problem... file\n");
        return false;
    }

#ifdef PNG
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t x, y, z;
    png_voidp* row_pointers = NULL;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(png_ptr == NULL){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    info_ptr = png_create_info_struct(png_ptr);
    if(info_ptr == NULL){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    /* Set up error handling. */

    if(setjmp(png_jmpbuf(png_ptr))){
        png_destroy_write_struct(&png_ptr, &info_ptr);
    }

    /* Set image attributes. */

    png_set_IHDR(png_ptr, info_ptr, _width, _height, COLOR_DEPTH,
            PNG_COLOR_TYPE_RGB,
            PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_DEFAULT,
            PNG_FILTER_TYPE_DEFAULT);

    /* Initialize rows of PNG. */

    row_pointers = (png_voidp*)png_malloc(png_ptr,
            _height * sizeof(png_byte *));
    int i = 0;
    for(y = 0;y < _height;++y){
        png_byte *row = (png_byte*)png_malloc(png_ptr,
                sizeof(uint8_t) * _width * PIXEL_SIZE);

        row_pointers[y] = row;
        for(x = 0;x < _width;++x){
            for(z = 0;z < PIXEL_SIZE;z++)
            *row++ = _image[i++] * 255.0f;
        }
    }

    /* Write the image data to "fp". */
    png_init_io(png_ptr, file);
    png_set_rows(png_ptr, info_ptr, (png_bytepp)row_pointers);
    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

    /* The routine has successfully written the file, so we set
     "status" to a value which indicates success. */

    for(y = 0;y < _height;y++){
        png_free(png_ptr, row_pointers[y]);
    }
    png_free(png_ptr, row_pointers);

#else
    fprintf(file, "P6\n%i %i\n255\n", _width, _height);

    std::vector<unsigned char> imageC(_image.size());

    for(unsigned int i = 0;i < _image.size();++i)
        imageC[i] = (unsigned char)(_image[i] * 255.0f);

    int t = fwrite(&(imageC[0]), _width * _height * PIXEL_SIZE, 1, file);
    if(t != 1){
        printf("Dump file problem... fwrite\n");
        return false;
    }
#endif

    fclose(file);
    printf("Wrote raytrace output to %s\n", filename);
    return true;
}
<|endoftext|>


<commit_before>/*==========================================================================
 * Copyright (c) 2005 University of Massachusetts.  All Rights Reserved.
 *
 * Use of the Lemur Toolkit for Language Modeling and Information Retrieval
 * is subject to the terms of the software license set forth in the LICENSE
 * file included with this software, and also available at
 * http://www.lemurproject.org/license.html
 *
 *==========================================================================
 */
// dmf
// C++ thread safe implementation of the Krovetz stemmer.
// requires no external data files.
// 07/29/2005
#ifndef _KROVETZ_STEMMER_H_
#define _KROVETZ_STEMMER_H_
#include <iostream>
#include <cstring>
#if defined(_WIN32)
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#include <hash_map>
#elif defined(__clang__)
#include <tr1/unordered_map>
#else
// Move this somewhere
#ifndef HAVE_GCC_VERSION
#define HAVE_GCC_VERSION(MAJOR, MINOR)                                  \
  (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
#endif /* ! HAVE_GCC_VERSION */
#if HAVE_GCC_VERSION(4,3)
// if GCC 4.3+
#include <tr1/unordered_map>
#else
#include <ext/hash_map>
#endif
// 3.3 does not use __gnu_cxx, 3.4+ does.
using namespace __gnu_cxx;
#endif

namespace stem {
  class KrovetzStemmer {
  public:
    KrovetzStemmer();
    ~KrovetzStemmer();
    /// maximum number of characters in a word to be stemmed.
    static const int MAX_WORD_LENGTH=25;
    /*!
      \brief stem a term using the Krovetz algorithm.
      The stem returned may be longer than the input term.
      May return a pointer
      to the private attribute stem. Performs case normalization on its
      input argument. Return values should be copied before
      calling the method again.
      @param term the term to stem
      @return the stemmed term or the original term if no stemming was
      performed.
    */
    char * kstem_stemmer(char *term);
    /*!
      \brief stem a term using the Krovetz algorithm into the specified
      buffer.
      The stem returned may be longer than the input term.
      Performs case normalization on its input argument.
      @param term the term to stem
      @param buffer the buffer to hold the stemmed term. The buffer should
      be at MAX_WORD_LENGTH or larger.
      @return the number of characters written to the buffer, including
      the terminating '\\0'. If 0, the caller should use the value in term.
    */
    int kstem_stem_tobuffer(char *term, char *buffer);
    /*!
      \brief Add an entry to the stemmer's dictionary table.
      @param variant the spelling for the entry.
      @param word the stem to use for the variant. If "", the variant
      stems to itself.
      @param exc Is the word an exception to the spelling rules.
    */
    void kstem_add_table_entry(const char* variant, const char* word,
                               bool exc=false);
  private:
    /// Dictionary table entry
    typedef struct dictEntry {
      /// is the word an exception to stemming rules?
      bool exception;
      /// stem to use for this entry.
      const char *root;
    } dictEntry;
    /// Two term hashtable entry for caching across calls
    typedef struct cacheEntry {
      /// flag for first or second entry most recently used.
      char flag;
      /// first entry variant
      char word1[MAX_WORD_LENGTH];
      /// first entry stem
      char stem1[MAX_WORD_LENGTH];
      /// second entry variant
      char word2[MAX_WORD_LENGTH];
      /// second entry stem
      char stem2[MAX_WORD_LENGTH];
    } cacheEntry;

    // operates on atribute word.
    bool ends(const char *s, int sufflen);
    void setsuff(const char *str, int length);
    dictEntry *getdep(char *word);
    bool lookup(char *word);
    bool cons(int i);
    bool vowelinstem();
    bool vowel(int i);
    bool doublec(int i);
    void plural();
    void past_tense();
    void aspect();
    void ion_endings();
    void er_and_or_endings ();
    void ly_endings ();
    void al_endings() ;
    void ive_endings() ;
    void ize_endings() ;
    void ment_endings() ;
    void ity_endings() ;
    void ble_endings() ;
    void ness_endings() ;
    void ism_endings();
    void ic_endings();
    void ncy_endings();
    void nce_endings();
    // maint.
    void loadTables();
#if defined(_WIN32)
    struct ltstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) < 0;
      }
    };
    //studio 7 hash_map provides hash_compare, rather than hash
    // needing an < predicate, rather than an == predicate.
    typedef stdext::hash_map<const char *, dictEntry, stdext::hash_compare<const char *, ltstr> > dictTable;
#elif defined(__clang__)
    struct eqstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) == 0;
      }
    };
    typedef std::tr1::unordered_map<const char *, dictEntry, std::tr1::hash<std::string>, eqstr> dictTable;
#else
    struct eqstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) == 0;
      }
    };
#if HAVE_GCC_VERSION(4,3)
    typedef std::tr1::unordered_map<const char *, dictEntry, std::tr1::hash<std::string>, eqstr> dictTable;
#else
    typedef hash_map<const char *, dictEntry, hash<const char *>, eqstr> dictTable;
#endif
#endif
    dictTable dictEntries;
    // this needs to be a bounded size cache.
    // kstem.cpp uses size 30013 entries.
    cacheEntry *stemCache;
    // size
    int stemhtsize;
    // state
    // k = wordlength - 1
    int k;
    // j is stemlength - 1
    int j;
    // pointer to the output buffer
    char *word;
    // used by kstem_stemmer to return a safe value.
    char stem[MAX_WORD_LENGTH];
  };
}
#endif /* _KROVETZ_STEMMER_H_*/
<commit_msg>Fixed the compatibility issue with Windows 64bit architecture<commit_after>/*==========================================================================
 * Copyright (c) 2005 University of Massachusetts.  All Rights Reserved.
 *
 * Use of the Lemur Toolkit for Language Modeling and Information Retrieval
 * is subject to the terms of the software license set forth in the LICENSE
 * file included with this software, and also available at
 * http://www.lemurproject.org/license.html
 *
 *==========================================================================
 */
// dmf
// C++ thread safe implementation of the Krovetz stemmer.
// requires no external data files.
// 07/29/2005
#ifndef _KROVETZ_STEMMER_H_
#define _KROVETZ_STEMMER_H_
#include <iostream>
#include <cstring>
#if defined(_WIN32) || defined(_WIN64)
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#include <hash_map>
#elif defined(__clang__)
#include <tr1/unordered_map>
#else
// Move this somewhere
#ifndef HAVE_GCC_VERSION
#define HAVE_GCC_VERSION(MAJOR, MINOR)                                  \
  (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
#endif /* ! HAVE_GCC_VERSION */
#if HAVE_GCC_VERSION(4,3)
// if GCC 4.3+
#include <tr1/unordered_map>
#else
#include <ext/hash_map>
#endif
// 3.3 does not use __gnu_cxx, 3.4+ does.
using namespace __gnu_cxx;
#endif

namespace stem {
  class KrovetzStemmer {
  public:
    KrovetzStemmer();
    ~KrovetzStemmer();
    /// maximum number of characters in a word to be stemmed.
    static const int MAX_WORD_LENGTH=25;
    /*!
      \brief stem a term using the Krovetz algorithm.
      The stem returned may be longer than the input term.
      May return a pointer
      to the private attribute stem. Performs case normalization on its
      input argument. Return values should be copied before
      calling the method again.
      @param term the term to stem
      @return the stemmed term or the original term if no stemming was
      performed.
    */
    char * kstem_stemmer(char *term);
    /*!
      \brief stem a term using the Krovetz algorithm into the specified
      buffer.
      The stem returned may be longer than the input term.
      Performs case normalization on its input argument.
      @param term the term to stem
      @param buffer the buffer to hold the stemmed term. The buffer should
      be at MAX_WORD_LENGTH or larger.
      @return the number of characters written to the buffer, including
      the terminating '\\0'. If 0, the caller should use the value in term.
    */
    int kstem_stem_tobuffer(char *term, char *buffer);
    /*!
      \brief Add an entry to the stemmer's dictionary table.
      @param variant the spelling for the entry.
      @param word the stem to use for the variant. If "", the variant
      stems to itself.
      @param exc Is the word an exception to the spelling rules.
    */
    void kstem_add_table_entry(const char* variant, const char* word,
                               bool exc=false);
  private:
    /// Dictionary table entry
    typedef struct dictEntry {
      /// is the word an exception to stemming rules?
      bool exception;
      /// stem to use for this entry.
      const char *root;
    } dictEntry;
    /// Two term hashtable entry for caching across calls
    typedef struct cacheEntry {
      /// flag for first or second entry most recently used.
      char flag;
      /// first entry variant
      char word1[MAX_WORD_LENGTH];
      /// first entry stem
      char stem1[MAX_WORD_LENGTH];
      /// second entry variant
      char word2[MAX_WORD_LENGTH];
      /// second entry stem
      char stem2[MAX_WORD_LENGTH];
    } cacheEntry;

    // operates on atribute word.
    bool ends(const char *s, int sufflen);
    void setsuff(const char *str, int length);
    dictEntry *getdep(char *word);
    bool lookup(char *word);
    bool cons(int i);
    bool vowelinstem();
    bool vowel(int i);
    bool doublec(int i);
    void plural();
    void past_tense();
    void aspect();
    void ion_endings();
    void er_and_or_endings ();
    void ly_endings ();
    void al_endings() ;
    void ive_endings() ;
    void ize_endings() ;
    void ment_endings() ;
    void ity_endings() ;
    void ble_endings() ;
    void ness_endings() ;
    void ism_endings();
    void ic_endings();
    void ncy_endings();
    void nce_endings();
    // maint.
    void loadTables();
#if defined(_WIN32)
    struct ltstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) < 0;
      }
    };
    //studio 7 hash_map provides hash_compare, rather than hash
    // needing an < predicate, rather than an == predicate.
    typedef stdext::hash_map<const char *, dictEntry, stdext::hash_compare<const char *, ltstr> > dictTable;
#elif defined(__clang__)
    struct eqstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) == 0;
      }
    };
    typedef std::tr1::unordered_map<const char *, dictEntry, std::tr1::hash<std::string>, eqstr> dictTable;
#else
    struct eqstr {
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) == 0;
      }
    };
#if HAVE_GCC_VERSION(4,3)
    typedef std::tr1::unordered_map<const char *, dictEntry, std::tr1::hash<std::string>, eqstr> dictTable;
#else
    typedef hash_map<const char *, dictEntry, hash<const char *>, eqstr> dictTable;
#endif
#endif
    dictTable dictEntries;
    // this needs to be a bounded size cache.
    // kstem.cpp uses size 30013 entries.
    cacheEntry *stemCache;
    // size
    int stemhtsize;
    // state
    // k = wordlength - 1
    int k;
    // j is stemlength - 1
    int j;
    // pointer to the output buffer
    char *word;
    // used by kstem_stemmer to return a safe value.
    char stem[MAX_WORD_LENGTH];
  };
}
#endif /* _KROVETZ_STEMMER_H_*/
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. 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.
 */

#include "config.h"
#include "bindings/v8/DOMWrapperWorld.h"

#include "V8Window.h"
#include "bindings/v8/DOMDataStore.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMActivityLogger.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8WindowShell.h"
#include "bindings/v8/WrapperTypeInfo.h"
#include "core/dom/ExecutionContext.h"
#include "wtf/HashTraits.h"
#include "wtf/MainThread.h"
#include "wtf/StdLibExtras.h"

namespace WebCore {

unsigned DOMWrapperWorld::isolatedWorldCount = 0;

PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::create(int worldId, int extensionGroup)
{
    return adoptRef(new DOMWrapperWorld(worldId, extensionGroup));
}

DOMWrapperWorld::DOMWrapperWorld(int worldId, int extensionGroup)
    : m_worldId(worldId)
    , m_extensionGroup(extensionGroup)
{
    if (isMainWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(MainWorld));
    else if (isIsolatedWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(IsolatedWorld));
    else if (isWorkerWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(WorkerWorld));
}

DOMWrapperWorld* DOMWrapperWorld::current(v8::Isolate* isolate)
{
    v8::Handle<v8::Context> context = isolate->GetCurrentContext();
    if (context.IsEmpty() || !contextHasCorrectPrototype(context))
        return 0;
    if (DOMWrapperWorld* world = isolatedWorld(context))
        return world;
    return mainWorld();
}

DOMWrapperWorld* DOMWrapperWorld::mainWorld()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_REF(DOMWrapperWorld, cachedMainWorld, (DOMWrapperWorld::create(MainWorldId, mainWorldExtensionGroup)));
    return cachedMainWorld;
}

typedef HashMap<int, DOMWrapperWorld*> WorldMap;
static WorldMap& isolatedWorldMap()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(WorldMap, map, ());
    return map;
}

void DOMWrapperWorld::getAllWorldsInMainThread(Vector<RefPtr<DOMWrapperWorld> >& worlds)
{
    ASSERT(isMainThread());
    worlds.append(mainWorld());
    WorldMap& isolatedWorlds = isolatedWorldMap();
    for (WorldMap::iterator it = isolatedWorlds.begin(); it != isolatedWorlds.end(); ++it)
        worlds.append(it->value);
}

DOMWrapperWorld::~DOMWrapperWorld()
{
    ASSERT(!isMainWorld());

    if (!isIsolatedWorld())
        return;

    WorldMap& map = isolatedWorldMap();
    WorldMap::iterator i = map.find(m_worldId);
    if (i == map.end()) {
        ASSERT_NOT_REACHED();
        return;
    }
    ASSERT(i->value == this);

    map.remove(i);
    isolatedWorldCount--;
    ASSERT(map.size() == isolatedWorldCount);
}

PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::ensureIsolatedWorld(int worldId, int extensionGroup)
{
    ASSERT(isIsolatedWorldId(worldId));

    WorldMap& map = isolatedWorldMap();
    WorldMap::AddResult result = map.add(worldId, 0);
    RefPtr<DOMWrapperWorld> world = result.storedValue->value;
    if (world) {
        ASSERT(world->worldId() == worldId);
        ASSERT(world->extensionGroup() == extensionGroup);
        return world.release();
    }

    world = DOMWrapperWorld::create(worldId, extensionGroup);
    result.storedValue->value = world.get();
    isolatedWorldCount++;
    ASSERT(map.size() == isolatedWorldCount);

    return world.release();
}

v8::Handle<v8::Context> DOMWrapperWorld::context(ScriptController& controller)
{
    return controller.windowShell(this)->context();
}

typedef HashMap<int, RefPtr<SecurityOrigin> > IsolatedWorldSecurityOriginMap;
static IsolatedWorldSecurityOriginMap& isolatedWorldSecurityOrigins()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(IsolatedWorldSecurityOriginMap, map, ());
    return map;
}

SecurityOrigin* DOMWrapperWorld::isolatedWorldSecurityOrigin()
{
    ASSERT(this->isIsolatedWorld());
    IsolatedWorldSecurityOriginMap& origins = isolatedWorldSecurityOrigins();
    IsolatedWorldSecurityOriginMap::iterator it = origins.find(worldId());
    return it == origins.end() ? 0 : it->value.get();
}

void DOMWrapperWorld::setIsolatedWorldSecurityOrigin(int worldId, PassRefPtr<SecurityOrigin> securityOrigin)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    if (securityOrigin)
        isolatedWorldSecurityOrigins().set(worldId, securityOrigin);
    else
        isolatedWorldSecurityOrigins().remove(worldId);
}

void DOMWrapperWorld::clearIsolatedWorldSecurityOrigin(int worldId)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    isolatedWorldSecurityOrigins().remove(worldId);
}

typedef HashMap<int, bool> IsolatedWorldContentSecurityPolicyMap;
static IsolatedWorldContentSecurityPolicyMap& isolatedWorldContentSecurityPolicies()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(IsolatedWorldContentSecurityPolicyMap, map, ());
    return map;
}

bool DOMWrapperWorld::isolatedWorldHasContentSecurityPolicy()
{
    ASSERT(this->isIsolatedWorld());
    IsolatedWorldContentSecurityPolicyMap& policies = isolatedWorldContentSecurityPolicies();
    IsolatedWorldContentSecurityPolicyMap::iterator it = policies.find(worldId());
    return it == policies.end() ? false : it->value;
}

void DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(int worldId, const String& policy)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    if (!policy.isEmpty())
        isolatedWorldContentSecurityPolicies().set(worldId, true);
    else
        isolatedWorldContentSecurityPolicies().remove(worldId);
}

void DOMWrapperWorld::clearIsolatedWorldContentSecurityPolicy(int worldId)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    isolatedWorldContentSecurityPolicies().remove(worldId);
}

typedef HashMap<int, OwnPtr<V8DOMActivityLogger>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int> > DOMActivityLoggerMap;
static DOMActivityLoggerMap& domActivityLoggers()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(DOMActivityLoggerMap, map, ());
    return map;
}

void DOMWrapperWorld::setActivityLogger(int worldId, PassOwnPtr<V8DOMActivityLogger> logger)
{
    domActivityLoggers().set(worldId, logger);
}

V8DOMActivityLogger* DOMWrapperWorld::activityLogger(int worldId)
{
    DOMActivityLoggerMap& loggers = domActivityLoggers();
    DOMActivityLoggerMap::iterator it = loggers.find(worldId);
    return it == loggers.end() ? 0 : it->value.get();
}

bool DOMWrapperWorld::contextHasCorrectPrototype(v8::Handle<v8::Context> context)
{
    return V8WindowShell::contextHasCorrectPrototype(context);
}

} // namespace WebCore
<commit_msg>Fix crashes after r167276<commit_after>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. 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.
 */

#include "config.h"
#include "bindings/v8/DOMWrapperWorld.h"

#include "V8Window.h"
#include "bindings/v8/DOMDataStore.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMActivityLogger.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8WindowShell.h"
#include "bindings/v8/WrapperTypeInfo.h"
#include "core/dom/ExecutionContext.h"
#include "wtf/HashTraits.h"
#include "wtf/MainThread.h"
#include "wtf/StdLibExtras.h"

namespace WebCore {

unsigned DOMWrapperWorld::isolatedWorldCount = 0;

PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::create(int worldId, int extensionGroup)
{
    return adoptRef(new DOMWrapperWorld(worldId, extensionGroup));
}

DOMWrapperWorld::DOMWrapperWorld(int worldId, int extensionGroup)
    : m_worldId(worldId)
    , m_extensionGroup(extensionGroup)
{
    if (isMainWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(MainWorld));
    else if (isIsolatedWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(IsolatedWorld));
    else if (isWorkerWorld())
        m_domDataStore = adoptPtr(new DOMDataStore(WorkerWorld));
}

DOMWrapperWorld* DOMWrapperWorld::current(v8::Isolate* isolate)
{
    v8::Handle<v8::Context> context = isolate->GetCurrentContext();
    if (context.IsEmpty() || !toDOMWindow(context))
        return 0;
    if (DOMWrapperWorld* world = isolatedWorld(context))
        return world;
    return mainWorld();
}

DOMWrapperWorld* DOMWrapperWorld::mainWorld()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_REF(DOMWrapperWorld, cachedMainWorld, (DOMWrapperWorld::create(MainWorldId, mainWorldExtensionGroup)));
    return cachedMainWorld;
}

typedef HashMap<int, DOMWrapperWorld*> WorldMap;
static WorldMap& isolatedWorldMap()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(WorldMap, map, ());
    return map;
}

void DOMWrapperWorld::getAllWorldsInMainThread(Vector<RefPtr<DOMWrapperWorld> >& worlds)
{
    ASSERT(isMainThread());
    worlds.append(mainWorld());
    WorldMap& isolatedWorlds = isolatedWorldMap();
    for (WorldMap::iterator it = isolatedWorlds.begin(); it != isolatedWorlds.end(); ++it)
        worlds.append(it->value);
}

DOMWrapperWorld::~DOMWrapperWorld()
{
    ASSERT(!isMainWorld());

    if (!isIsolatedWorld())
        return;

    WorldMap& map = isolatedWorldMap();
    WorldMap::iterator i = map.find(m_worldId);
    if (i == map.end()) {
        ASSERT_NOT_REACHED();
        return;
    }
    ASSERT(i->value == this);

    map.remove(i);
    isolatedWorldCount--;
    ASSERT(map.size() == isolatedWorldCount);
}

PassRefPtr<DOMWrapperWorld> DOMWrapperWorld::ensureIsolatedWorld(int worldId, int extensionGroup)
{
    ASSERT(isIsolatedWorldId(worldId));

    WorldMap& map = isolatedWorldMap();
    WorldMap::AddResult result = map.add(worldId, 0);
    RefPtr<DOMWrapperWorld> world = result.storedValue->value;
    if (world) {
        ASSERT(world->worldId() == worldId);
        ASSERT(world->extensionGroup() == extensionGroup);
        return world.release();
    }

    world = DOMWrapperWorld::create(worldId, extensionGroup);
    result.storedValue->value = world.get();
    isolatedWorldCount++;
    ASSERT(map.size() == isolatedWorldCount);

    return world.release();
}

v8::Handle<v8::Context> DOMWrapperWorld::context(ScriptController& controller)
{
    return controller.windowShell(this)->context();
}

typedef HashMap<int, RefPtr<SecurityOrigin> > IsolatedWorldSecurityOriginMap;
static IsolatedWorldSecurityOriginMap& isolatedWorldSecurityOrigins()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(IsolatedWorldSecurityOriginMap, map, ());
    return map;
}

SecurityOrigin* DOMWrapperWorld::isolatedWorldSecurityOrigin()
{
    ASSERT(this->isIsolatedWorld());
    IsolatedWorldSecurityOriginMap& origins = isolatedWorldSecurityOrigins();
    IsolatedWorldSecurityOriginMap::iterator it = origins.find(worldId());
    return it == origins.end() ? 0 : it->value.get();
}

void DOMWrapperWorld::setIsolatedWorldSecurityOrigin(int worldId, PassRefPtr<SecurityOrigin> securityOrigin)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    if (securityOrigin)
        isolatedWorldSecurityOrigins().set(worldId, securityOrigin);
    else
        isolatedWorldSecurityOrigins().remove(worldId);
}

void DOMWrapperWorld::clearIsolatedWorldSecurityOrigin(int worldId)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    isolatedWorldSecurityOrigins().remove(worldId);
}

typedef HashMap<int, bool> IsolatedWorldContentSecurityPolicyMap;
static IsolatedWorldContentSecurityPolicyMap& isolatedWorldContentSecurityPolicies()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(IsolatedWorldContentSecurityPolicyMap, map, ());
    return map;
}

bool DOMWrapperWorld::isolatedWorldHasContentSecurityPolicy()
{
    ASSERT(this->isIsolatedWorld());
    IsolatedWorldContentSecurityPolicyMap& policies = isolatedWorldContentSecurityPolicies();
    IsolatedWorldContentSecurityPolicyMap::iterator it = policies.find(worldId());
    return it == policies.end() ? false : it->value;
}

void DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(int worldId, const String& policy)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    if (!policy.isEmpty())
        isolatedWorldContentSecurityPolicies().set(worldId, true);
    else
        isolatedWorldContentSecurityPolicies().remove(worldId);
}

void DOMWrapperWorld::clearIsolatedWorldContentSecurityPolicy(int worldId)
{
    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldId));
    isolatedWorldContentSecurityPolicies().remove(worldId);
}

typedef HashMap<int, OwnPtr<V8DOMActivityLogger>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int> > DOMActivityLoggerMap;
static DOMActivityLoggerMap& domActivityLoggers()
{
    ASSERT(isMainThread());
    DEFINE_STATIC_LOCAL(DOMActivityLoggerMap, map, ());
    return map;
}

void DOMWrapperWorld::setActivityLogger(int worldId, PassOwnPtr<V8DOMActivityLogger> logger)
{
    domActivityLoggers().set(worldId, logger);
}

V8DOMActivityLogger* DOMWrapperWorld::activityLogger(int worldId)
{
    DOMActivityLoggerMap& loggers = domActivityLoggers();
    DOMActivityLoggerMap::iterator it = loggers.find(worldId);
    return it == loggers.end() ? 0 : it->value.get();
}

bool DOMWrapperWorld::contextHasCorrectPrototype(v8::Handle<v8::Context> context)
{
    return V8WindowShell::contextHasCorrectPrototype(context);
}

} // namespace WebCore
<|endoftext|>


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

/// \file
/// Tests for the ReplayPoseDevice class.

#include <memory>
#include <string>

#include <gtest/gtest.h>

#include <boost/thread/thread.hpp> // This is to access boost::this_thread namespace

#include "SurgSim/Devices/ReplayPoseDevice/ReplayPoseDevice.h"
#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/Framework/Timer.h"
#include "SurgSim/Math/RigidTransform.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Testing/MockInputOutput.h"

using SurgSim::Devices::ReplayPoseDevice;
using SurgSim::DataStructures::DataGroup;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::Matrix44d;
using SurgSim::Testing::MockInputOutput;

namespace
{
void createFakeRecord(const std::string& fileName, double rate)
{
	SurgSim::Framework::Timer timer;
	timer.setMaxNumberOfFrames(1);
	timer.start();

	std::ofstream f(fileName, std::ios::out | std::ios::trunc);

	timer.endFrame();
	double cumulativeTime = timer.getLastFramePeriod();
	double deltaTime = 1.0 / rate;

	SurgSim::Math::Quaterniond q(Eigen::AngleAxisd(2.0123, SurgSim::Math::Vector3d(1, 2, 3).normalized()));
	SurgSim::Math::Vector3d t(0.01, -0.04, 0.0035);
	SurgSim::Math::RigidTransform3d poseStart = SurgSim::Math::makeRigidTranslation(SurgSim::Math::Vector3d::Zero());
	SurgSim::Math::RigidTransform3d poseEnd = SurgSim::Math::makeRigidTransform(q, t);

	do
	{
		auto pose = SurgSim::Math::interpolate(poseStart, poseEnd, cumulativeTime);
		f << cumulativeTime << " " << pose.matrix() << std::endl;
		cumulativeTime += deltaTime;
	} while (cumulativeTime < 1.0);
	f << "1.0 " << poseEnd.matrix() << std::endl;

	f.close();
}

bool exist(const std::string& fileName)
{
	std::ifstream f(fileName.c_str());
	bool result = f.good();
	f.close();
	return result;
}

void clearFakeRecord(const std::string& fileName)
{
	if (exist(fileName))
	{
		std::remove(fileName.c_str());
	}
}
}

TEST(ReplayPoseDeviceTest, Name)
{
	auto device = std::make_shared<ReplayPoseDevice>("FakeReplayDevice");
	EXPECT_EQ("FakeReplayDevice", device->getName());
}

TEST(ReplayPoseDeviceTest, Factory)
{
	std::shared_ptr<SurgSim::Input::DeviceInterface> device;
	ASSERT_NO_THROW(device = SurgSim::Input::DeviceInterface::getFactory().create(
		"SurgSim::Devices::ReplayPoseDevice", "Device"));
	EXPECT_NE(nullptr, device);
}

namespace
{
void AddInputConsumerRecordXHzReplayYHz(double rateRecord, double rateReplay)
{
	std::string fileName("FakeRecord.txt");

	createFakeRecord(fileName, rateRecord);

	std::shared_ptr<ReplayPoseDevice> device = std::make_shared<ReplayPoseDevice>("MyReplayPoseDevice");
	ASSERT_TRUE(device != nullptr) << "Device creation failed.";
	device->setRate(rateReplay);
	device->setFileName("FakeRecord.txt");
	ASSERT_TRUE(device->initialize()) << "Initialization failed.";

	std::shared_ptr<MockInputOutput> consumer = std::make_shared<MockInputOutput>();
	EXPECT_EQ(0, consumer->m_numTimesInitializedInput);
	EXPECT_EQ(0, consumer->m_numTimesReceivedInput);

	EXPECT_FALSE(device->removeInputConsumer(consumer));
	EXPECT_EQ(0, consumer->m_numTimesInitializedInput);
	EXPECT_EQ(0, consumer->m_numTimesReceivedInput);

	EXPECT_TRUE(device->addInputConsumer(consumer));

	// Adding the same input consumer again should fail.
	EXPECT_FALSE(device->addInputConsumer(consumer));

	// Sleep for a second, to see how many times the consumer is invoked.
	boost::this_thread::sleep_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000));

	// Check the number of invocations.
	EXPECT_EQ(1, consumer->m_numTimesInitializedInput);
	EXPECT_GE(consumer->m_numTimesReceivedInput, rateReplay * 0.8); // rateReplay@ 1000Hz => lower limit@ 800Hz
	EXPECT_LE(consumer->m_numTimesReceivedInput, rateReplay * 1.2); // rateReplay@ 1000Hz => higher limit@ 1200Hz

	EXPECT_TRUE(consumer->m_lastReceivedInput.poses().hasData(SurgSim::DataStructures::Names::POSE));

	// Check the replay pose passed 1.0 second
	SurgSim::Math::RigidTransform3d pose;
	boost::this_thread::sleep_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50));
	ASSERT_TRUE(consumer->m_lastReceivedInput.poses().get(SurgSim::DataStructures::Names::POSE, &pose));
	SurgSim::Math::Quaterniond q(Eigen::AngleAxisd(2.0123, SurgSim::Math::Vector3d(1, 2, 3).normalized()));
	SurgSim::Math::Vector3d t(0.01, -0.04, 0.0035);
	SurgSim::Math::RigidTransform3d poseEnd = SurgSim::Math::makeRigidTransform(q, t);
	EXPECT_NEAR(0, (pose.matrix() - poseEnd.matrix()).norm(), 1e-6);

	EXPECT_TRUE(device->removeInputConsumer(consumer));
	// Removing the same input consumer again should fail.
	EXPECT_FALSE(device->removeInputConsumer(consumer));

	clearFakeRecord(fileName);
}
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord60HzReplay60Hz)
{
	AddInputConsumerRecordXHzReplayYHz(60.0, 60.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord60HzReplay1000Hz)
{
	AddInputConsumerRecordXHzReplayYHz(60.0, 1000.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord1000HzReplay60Hz)
{
	AddInputConsumerRecordXHzReplayYHz(1000.0, 60.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord1000HzReplay1000Hz)
{
	AddInputConsumerRecordXHzReplayYHz(1000.0, 1000.0);
}
<commit_msg>Update ReplayPoseDevice unit tests<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// \file
/// Tests for the ReplayPoseDevice class.

#include <memory>
#include <string>

#include <gtest/gtest.h>

#include <boost/thread/thread.hpp> // This is to access boost::this_thread namespace

#include "SurgSim/Devices/ReplayPoseDevice/ReplayPoseDevice.h"
#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/Framework/Timer.h"
#include "SurgSim/Math/RigidTransform.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Testing/MockInputOutput.h"

using SurgSim::Devices::ReplayPoseDevice;
using SurgSim::DataStructures::DataGroup;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::Matrix44d;
using SurgSim::Testing::MockInputOutput;

namespace
{
void createFakeRecord(const std::string& fileName, double rate)
{
	SurgSim::Framework::Timer timer;
	timer.setMaxNumberOfFrames(1);
	timer.start();

	std::ofstream f(fileName, std::ios::out | std::ios::trunc);

	timer.endFrame();
	double cumulativeTime = timer.getLastFramePeriod();
	double deltaTime = 1.0 / rate;

	SurgSim::Math::Quaterniond q(Eigen::AngleAxisd(2.0123, SurgSim::Math::Vector3d(1, 2, 3).normalized()));
	SurgSim::Math::Vector3d t(0.01, -0.04, 0.0035);
	SurgSim::Math::RigidTransform3d poseStart = SurgSim::Math::makeRigidTranslation(SurgSim::Math::Vector3d::Zero());
	SurgSim::Math::RigidTransform3d poseEnd = SurgSim::Math::makeRigidTransform(q, t);

	do
	{
		auto pose = SurgSim::Math::interpolate(poseStart, poseEnd, cumulativeTime);
		f << cumulativeTime << std::endl << pose.matrix() << std::endl;
		cumulativeTime += deltaTime;
	} while (cumulativeTime < 1.0);
	f << "1.0" << std::endl << poseEnd.matrix() << std::endl;

	f.close();
}

bool exist(const std::string& fileName)
{
	std::ifstream f(fileName.c_str());
	bool result = f.good();
	f.close();
	return result;
}

void clearFakeRecord(const std::string& fileName)
{
	if (exist(fileName))
	{
		std::remove(fileName.c_str());
	}
}
}

TEST(ReplayPoseDeviceTest, Name)
{
	auto device = std::make_shared<ReplayPoseDevice>("FakeReplayDevice");
	EXPECT_EQ("FakeReplayDevice", device->getName());
}

TEST(ReplayPoseDeviceTest, Filename)
{
	std::string fileName("FakeRecord.txt");
	createFakeRecord(fileName, 30);

	auto device = std::make_shared<ReplayPoseDevice>("FakeReplayDevice");
	EXPECT_EQ(0, device->getFileName().compare("ReplayPoseDevice.txt"));
	EXPECT_NO_THROW(device->setFileName(fileName));
	EXPECT_EQ(0, device->getFileName().compare(fileName));

	EXPECT_TRUE(device->initialize());

	clearFakeRecord(fileName);
	EXPECT_THROW(device->setFileName(fileName), SurgSim::Framework::AssertionFailure);
}

TEST(ReplayPoseDeviceTest, Initialize)
{
	std::string fileName("FakeRecord.txt");
	clearFakeRecord(fileName);

	{
		SCOPED_TRACE("Missing filename");
		auto device = std::make_shared<ReplayPoseDevice>("FakeReplayDevice");
		device->setFileName(fileName);
		EXPECT_FALSE(device->initialize()); // Missing the setFilename call, no file open
		EXPECT_FALSE(device->isInitialized());
	}
	{
		SCOPED_TRACE("Success");
		createFakeRecord(fileName, 30);

		auto device = std::make_shared<ReplayPoseDevice>("FakeReplayDevice");
		device->setFileName(fileName);
		EXPECT_TRUE(device->initialize());
		EXPECT_TRUE(device->isInitialized());

		clearFakeRecord(fileName);
	}
}

TEST(ReplayPoseDeviceTest, Factory)
{
	std::shared_ptr<SurgSim::Input::DeviceInterface> device;
	ASSERT_NO_THROW(device = SurgSim::Input::DeviceInterface::getFactory().create(
		"SurgSim::Devices::ReplayPoseDevice", "Device"));
	EXPECT_NE(nullptr, device);
}

namespace
{
void AddInputConsumerRecordXHzReplayYHz(double rateRecord, double rateReplay)
{
	std::string fileName("FakeRecord.txt");

	createFakeRecord(fileName, rateRecord);

	std::shared_ptr<ReplayPoseDevice> device = std::make_shared<ReplayPoseDevice>("MyReplayPoseDevice");
	ASSERT_TRUE(device != nullptr) << "Device creation failed.";
	device->setRate(rateReplay);
	device->setFileName("FakeRecord.txt");
	ASSERT_TRUE(device->initialize()) << "Initialization failed.";

	std::shared_ptr<MockInputOutput> consumer = std::make_shared<MockInputOutput>();
	EXPECT_EQ(0, consumer->m_numTimesInitializedInput);
	EXPECT_EQ(0, consumer->m_numTimesReceivedInput);

	EXPECT_FALSE(device->removeInputConsumer(consumer));
	EXPECT_EQ(0, consumer->m_numTimesInitializedInput);
	EXPECT_EQ(0, consumer->m_numTimesReceivedInput);

	EXPECT_TRUE(device->addInputConsumer(consumer));

	// Adding the same input consumer again should fail.
	EXPECT_FALSE(device->addInputConsumer(consumer));

	// Sleep for a second, to see how many times the consumer is invoked.
	boost::this_thread::sleep_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000));

	// Check the number of invocations.
	EXPECT_EQ(1, consumer->m_numTimesInitializedInput);
	EXPECT_GE(consumer->m_numTimesReceivedInput, rateReplay * 0.8); // rateReplay@ 1000Hz => lower limit@ 800Hz
	EXPECT_LE(consumer->m_numTimesReceivedInput, rateReplay * 1.2); // rateReplay@ 1000Hz => higher limit@ 1200Hz

	EXPECT_TRUE(consumer->m_lastReceivedInput.poses().hasData(SurgSim::DataStructures::Names::POSE));

	// Check the replay pose passed 1.0 second
	SurgSim::Math::RigidTransform3d pose;
	boost::this_thread::sleep_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(50));
	ASSERT_TRUE(consumer->m_lastReceivedInput.poses().get(SurgSim::DataStructures::Names::POSE, &pose));
	SurgSim::Math::Quaterniond q(Eigen::AngleAxisd(2.0123, SurgSim::Math::Vector3d(1, 2, 3).normalized()));
	SurgSim::Math::Vector3d t(0.01, -0.04, 0.0035);
	SurgSim::Math::RigidTransform3d poseEnd = SurgSim::Math::makeRigidTransform(q, t);
	EXPECT_NEAR(0, (pose.matrix() - poseEnd.matrix()).norm(), 1e-6);

	EXPECT_TRUE(device->removeInputConsumer(consumer));
	// Removing the same input consumer again should fail.
	EXPECT_FALSE(device->removeInputConsumer(consumer));

	clearFakeRecord(fileName);
}
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord60HzReplay60Hz)
{
	AddInputConsumerRecordXHzReplayYHz(60.0, 60.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord60HzReplay1000Hz)
{
	AddInputConsumerRecordXHzReplayYHz(60.0, 1000.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord1000HzReplay60Hz)
{
	AddInputConsumerRecordXHzReplayYHz(1000.0, 60.0);
}

TEST(ReplayPoseDeviceTest, AddInputConsumerRecord1000HzReplay1000Hz)
{
	AddInputConsumerRecordXHzReplayYHz(1000.0, 1000.0);
}
<|endoftext|>


<commit_before>//
// Created by kanairen on 2016/06/13.
//

#import "Layer.h"

const vector<vector<float>> &Layer::forward(vector<vector<float>> &input) {
    for (int i_data = 0; i_data < n_data; ++i_data) {
        for (int i_out = 0; i_out < n_out; ++i_out) {
            for (int i_in = 0; i_in < n_in; ++i_in) {
                out_forward[i_out][i_data] =
                        activation(weights[i_out][i_in] * input[i_in][i_data] +
                                   biases[i_out]);
            }
        }
    }
    return out_forward;
}

<commit_msg>add Layerコンストラクタを追加<commit_after>//
// Created by kanairen on 2016/06/13.
//

#import "Layer.h"

Layer::Layer(unsigned int n_data, unsigned int n_in, unsigned int n_out,
             float (*activation)(float), float (*grad_activation)(float)) :
        n_data(n_data), n_in(n_in), n_out(n_out), activation(activation),
        grad_activation(grad_activation),
        weights(vector<vector<float>>(n_out, vector<float>(n_in, 0.f))),
        biases(vector<float>(n_out, 0.f)),
        delta(vector<vector<float>>(n_out, vector<float>(n_data, 0.f))),
        u(vector<vector<float>>(n_out, vector<float>(n_data, 0.f))),
        z(vector<vector<float>>(n_out, vector<float>(n_data, 0.f))) {

    std::random_device rnd;
    std::mt19937 mt(rnd());
    std::uniform_real_distribution<> uniform(-sqrt(6. / (n_in + n_out)),
                                             sqrt(6. / (n_in + n_out)));
    for (int i = 0; i < n_out; ++i) {
        for (int j = 0; j < n_in; ++j) {
            weights[i][j] = uniform(mt);
        }
    }

}

const vector<vector<float>> &Layer::forward(vector<vector<float>> &input) {
    for (int i_data = 0; i_data < n_data; ++i_data) {
        for (int i_out = 0; i_out < n_out; ++i_out) {
            for (int i_in = 0; i_in < n_in; ++i_in) {
                out_forward[i_out][i_data] =
                        activation(weights[i_out][i_in] * input[i_in][i_data] +
                                   biases[i_out]);
            }
        }
    }
    return out_forward;
}

<|endoftext|>


<commit_before>#include "cnn/edges.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/lstm-fast.h"
#include "cnn/dict.h"

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;
using namespace cnn;

unsigned LAYERS = 2;
unsigned INPUT_DIM = 8;
unsigned HIDDEN_DIM = 24;
unsigned VOCAB_SIZE = 0;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLanguageModel {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLanguageModel(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, Dim({INPUT_DIM}));
    p_R = model.add_parameters(Dim({VOCAB_SIZE, HIDDEN_DIM}));
    p_bias = model.add_parameters(Dim({VOCAB_SIZE}));
  }

  // return VariableIndex of total loss
  VariableIndex BuildLMGraph(const vector<int>& sent, Hypergraph& hg) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph();  // reset RNN builder for new graph
    builder.add_parameter_edges(&hg);  // add variables for its parameters
    builder.start_new_sequence(&hg);
    VariableIndex i_R = hg.add_parameter(p_R); // hidden -> word rep parameter
    VariableIndex i_bias = hg.add_parameter(p_bias);  // word bias
    vector<VariableIndex> errs;
    for (unsigned t = 0; t < slen; ++t) {
      // x_t = lookup sent[t] in parameters p_c
      VariableIndex i_x_t = hg.add_lookup(p_c, sent[t]);
      // y_t = RNN(x_t)
      VariableIndex i_y_t = builder.add_input(i_x_t, &hg);
      // r_t = bias + R * y_t
      VariableIndex i_r_t = hg.add_function<Multilinear>({i_bias, i_R, i_y_t});
      // ydist = softmax(r_t)
      VariableIndex i_ydist = hg.add_function<LogSoftmax>({i_r_t});
      errs.push_back(hg.add_function<PickElement>({i_ydist}, sent[t+1]));
    }
    VariableIndex i_nerr = hg.add_function<Sum>(errs);
    return hg.add_function<Negate>({i_nerr});
  }

  // return VariableIndex of total loss
  void RandomSample(int max_len = 150) {
    cerr << endl;
    Hypergraph hg;
    builder.new_graph();  // reset RNN builder for new graph
    builder.add_parameter_edges(&hg);  // add variables for its parameters
    builder.start_new_sequence(&hg);
    VariableIndex i_R = hg.add_parameter(p_R); // hidden -> word rep parameter
    VariableIndex i_bias = hg.add_parameter(p_bias);  // word bias
    vector<VariableIndex> errs;
    int len = 0;
    int cur = kSOS;
    while(len < max_len && cur != kEOS) {
      ++len;
      // x_t = lookup sent[t] in parameters p_c
      VariableIndex i_x_t = hg.add_lookup(p_c, cur);
      // y_t = RNN(x_t)
      VariableIndex i_y_t = builder.add_input(i_x_t, &hg);
      // r_t = bias + R * y_t
      VariableIndex i_r_t = hg.add_function<Multilinear>({i_bias, i_R, i_y_t});
      // ydist = softmax(r_t)
      hg.add_function<Softmax>({i_r_t});
      unsigned w = 0;
      while (w == 0 || (int)w == kSOS) {
        auto dist = as_vector(hg.incremental_forward());
        double p = (double)rand() / (RAND_MAX + 1.0);
        for (; w < dist.size(); ++w) {
          p -= dist[w];
          if (p < 0.0) { break; }
        }
        if (w == dist.size()) w = kEOS;
      }
      cerr << (len == 1 ? "" : " ") << d.Convert(w);
      cur = w;
    }
    cerr << endl;
  }
};

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv);
  if (argc != 3 && argc != 4) {
    cerr << "Usage: " << argv[0] << " corpus.txt dev.txt [model.params]\n";
    return 1;
  }
  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  vector<vector<int>> training, dev;
  string line;
  int tlc = 0;
  int ttoks = 0;
  cerr << "Reading training data from " << argv[1] << "...\n";
  {
    ifstream in(argv[1]);
    assert(in);
    while(getline(in, line)) {
      ++tlc;
      training.push_back(ReadSentence(line, &d));
      ttoks += training.back().size();
      if (training.back().front() != kSOS && training.back().back() != kEOS) {
        cerr << "Training sentence in " << argv[1] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << tlc << " lines, " << ttoks << " tokens, " << d.size() << " types\n";
  }
  d.Freeze(); // no new word types allowed
  VOCAB_SIZE = d.size();

  int dlc = 0;
  int dtoks = 0;
  cerr << "Reading dev data from " << argv[2] << "...\n";
  {
    ifstream in(argv[2]);
    assert(in);
    while(getline(in, line)) {
      ++dlc;
      dev.push_back(ReadSentence(line, &d));
      dtoks += dev.back().size();
      if (dev.back().front() != kSOS && dev.back().back() != kEOS) {
        cerr << "Dev sentence in " << argv[2] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << dlc << " lines, " << dtoks << " tokens\n";
  }
  ostringstream os;
  os << "lm"
     << '_' << LAYERS
     << '_' << INPUT_DIM
     << '_' << HIDDEN_DIM
     << "-pid" << getpid() << ".params";
  const string fname = os.str();
  cerr << "Parameters will be written to: " << fname << endl;
  double best = 9e+99;

  Model model;
  bool use_momentum = false;
  Trainer* sgd = nullptr;
  if (use_momentum)
    sgd = new MomentumSGDTrainer(&model);
  else
    sgd = new SimpleSGDTrainer(&model);

  //RNNBuilder rnn(LAYERS, INPUT_DIM, HIDDEN_DIM, &model);
  RNNLanguageModel<LSTMBuilder_CIFG> lm(model);
  if (argc == 4) {
    string fname = argv[3];
    ifstream in(fname);
    boost::archive::text_iarchive ia(in);
    ia >> model;
  }

  unsigned report_every_i = 50;
  unsigned dev_every_i_reports = 500;
  unsigned si = training.size();
  vector<unsigned> order(training.size());
  for (unsigned i = 0; i < order.size(); ++i) order[i] = i;
  bool first = true;
  int report = 0;
  unsigned lines = 0;
  while(1) {
    Timer iteration("completed in");
    double loss = 0;
    unsigned chars = 0;
    for (unsigned i = 0; i < report_every_i; ++i) {
      if (si == training.size()) {
        si = 0;
        if (first) { first = false; } else { sgd->update_epoch(); }
        cerr << "**SHUFFLE\n";
        random_shuffle(order.begin(), order.end());
      }

      // build graph for this instance
      Hypergraph hg;
      auto& sent = training[order[si]];
      chars += sent.size() - 1;
      ++si;
      lm.BuildLMGraph(sent, hg);
      loss += as_scalar(hg.forward());
      hg.backward();
      sgd->update();
      ++lines;
    }
    sgd->status();
    cerr << " E = " << (loss / chars) << " ppl=" << exp(loss / chars) << ' ';
    lm.RandomSample();

    // show score on dev data?
    report++;
    if (report % dev_every_i_reports == 0) {
      double dloss = 0;
      int dchars = 0;
      for (auto& sent : dev) {
        Hypergraph hg;
        lm.BuildLMGraph(sent, hg);
        dloss += as_scalar(hg.forward());
        dchars += sent.size() - 1;
      }
      if (dloss < best) {
        best = dloss;
        ofstream out(fname);
        boost::archive::text_oarchive oa(out);
        oa << model;
      }
      cerr << "\n***DEV [epoch=" << (lines / (double)training.size()) << "] E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
    }
  }
  delete sgd;
}

<commit_msg>use cleaner interface<commit_after>#include "cnn/edges.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/lstm-fast.h"
#include "cnn/dict.h"

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;
using namespace cnn;

unsigned LAYERS = 2;
unsigned INPUT_DIM = 8;
unsigned HIDDEN_DIM = 24;
unsigned VOCAB_SIZE = 0;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLanguageModel {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLanguageModel(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, {INPUT_DIM});
    p_R = model.add_parameters({VOCAB_SIZE, HIDDEN_DIM});
    p_bias = model.add_parameters({VOCAB_SIZE});
  }

  // return VariableIndex of total loss
  VariableIndex BuildLMGraph(const vector<int>& sent, Hypergraph& hg) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph();  // reset RNN builder for new graph
    builder.add_parameter_edges(&hg);  // add variables for its parameters
    builder.start_new_sequence(&hg);
    VariableIndex i_R = hg.add_parameter(p_R); // hidden -> word rep parameter
    VariableIndex i_bias = hg.add_parameter(p_bias);  // word bias
    vector<VariableIndex> errs;
    for (unsigned t = 0; t < slen; ++t) {
      // x_t = lookup sent[t] in parameters p_c
      VariableIndex i_x_t = hg.add_lookup(p_c, sent[t]);
      // y_t = RNN(x_t)
      VariableIndex i_y_t = builder.add_input(i_x_t, &hg);
      // r_t = bias + R * y_t
      VariableIndex i_r_t = hg.add_function<Multilinear>({i_bias, i_R, i_y_t});
      // ydist = softmax(r_t)
      VariableIndex i_ydist = hg.add_function<LogSoftmax>({i_r_t});
      errs.push_back(hg.add_function<PickElement>({i_ydist}, sent[t+1]));
    }
    VariableIndex i_nerr = hg.add_function<Sum>(errs);
    return hg.add_function<Negate>({i_nerr});
  }

  // return VariableIndex of total loss
  void RandomSample(int max_len = 150) {
    cerr << endl;
    Hypergraph hg;
    builder.new_graph();  // reset RNN builder for new graph
    builder.add_parameter_edges(&hg);  // add variables for its parameters
    builder.start_new_sequence(&hg);
    VariableIndex i_R = hg.add_parameter(p_R); // hidden -> word rep parameter
    VariableIndex i_bias = hg.add_parameter(p_bias);  // word bias
    vector<VariableIndex> errs;
    int len = 0;
    int cur = kSOS;
    while(len < max_len && cur != kEOS) {
      ++len;
      // x_t = lookup sent[t] in parameters p_c
      VariableIndex i_x_t = hg.add_lookup(p_c, cur);
      // y_t = RNN(x_t)
      VariableIndex i_y_t = builder.add_input(i_x_t, &hg);
      // r_t = bias + R * y_t
      VariableIndex i_r_t = hg.add_function<Multilinear>({i_bias, i_R, i_y_t});
      // ydist = softmax(r_t)
      hg.add_function<Softmax>({i_r_t});
      unsigned w = 0;
      while (w == 0 || (int)w == kSOS) {
        auto dist = as_vector(hg.incremental_forward());
        double p = (double)rand() / (RAND_MAX + 1.0);
        for (; w < dist.size(); ++w) {
          p -= dist[w];
          if (p < 0.0) { break; }
        }
        if (w == dist.size()) w = kEOS;
      }
      cerr << (len == 1 ? "" : " ") << d.Convert(w);
      cur = w;
    }
    cerr << endl;
  }
};

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv);
  if (argc != 3 && argc != 4) {
    cerr << "Usage: " << argv[0] << " corpus.txt dev.txt [model.params]\n";
    return 1;
  }
  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  vector<vector<int>> training, dev;
  string line;
  int tlc = 0;
  int ttoks = 0;
  cerr << "Reading training data from " << argv[1] << "...\n";
  {
    ifstream in(argv[1]);
    assert(in);
    while(getline(in, line)) {
      ++tlc;
      training.push_back(ReadSentence(line, &d));
      ttoks += training.back().size();
      if (training.back().front() != kSOS && training.back().back() != kEOS) {
        cerr << "Training sentence in " << argv[1] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << tlc << " lines, " << ttoks << " tokens, " << d.size() << " types\n";
  }
  d.Freeze(); // no new word types allowed
  VOCAB_SIZE = d.size();

  int dlc = 0;
  int dtoks = 0;
  cerr << "Reading dev data from " << argv[2] << "...\n";
  {
    ifstream in(argv[2]);
    assert(in);
    while(getline(in, line)) {
      ++dlc;
      dev.push_back(ReadSentence(line, &d));
      dtoks += dev.back().size();
      if (dev.back().front() != kSOS && dev.back().back() != kEOS) {
        cerr << "Dev sentence in " << argv[2] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << dlc << " lines, " << dtoks << " tokens\n";
  }
  ostringstream os;
  os << "lm"
     << '_' << LAYERS
     << '_' << INPUT_DIM
     << '_' << HIDDEN_DIM
     << "-pid" << getpid() << ".params";
  const string fname = os.str();
  cerr << "Parameters will be written to: " << fname << endl;
  double best = 9e+99;

  Model model;
  bool use_momentum = false;
  Trainer* sgd = nullptr;
  if (use_momentum)
    sgd = new MomentumSGDTrainer(&model);
  else
    sgd = new SimpleSGDTrainer(&model);

  //RNNBuilder rnn(LAYERS, INPUT_DIM, HIDDEN_DIM, &model);
  RNNLanguageModel<LSTMBuilder_CIFG> lm(model);
  if (argc == 4) {
    string fname = argv[3];
    ifstream in(fname);
    boost::archive::text_iarchive ia(in);
    ia >> model;
  }

  unsigned report_every_i = 50;
  unsigned dev_every_i_reports = 500;
  unsigned si = training.size();
  vector<unsigned> order(training.size());
  for (unsigned i = 0; i < order.size(); ++i) order[i] = i;
  bool first = true;
  int report = 0;
  unsigned lines = 0;
  while(1) {
    Timer iteration("completed in");
    double loss = 0;
    unsigned chars = 0;
    for (unsigned i = 0; i < report_every_i; ++i) {
      if (si == training.size()) {
        si = 0;
        if (first) { first = false; } else { sgd->update_epoch(); }
        cerr << "**SHUFFLE\n";
        random_shuffle(order.begin(), order.end());
      }

      // build graph for this instance
      Hypergraph hg;
      auto& sent = training[order[si]];
      chars += sent.size() - 1;
      ++si;
      lm.BuildLMGraph(sent, hg);
      loss += as_scalar(hg.forward());
      hg.backward();
      sgd->update();
      ++lines;
    }
    sgd->status();
    cerr << " E = " << (loss / chars) << " ppl=" << exp(loss / chars) << ' ';
    lm.RandomSample();

    // show score on dev data?
    report++;
    if (report % dev_every_i_reports == 0) {
      double dloss = 0;
      int dchars = 0;
      for (auto& sent : dev) {
        Hypergraph hg;
        lm.BuildLMGraph(sent, hg);
        dloss += as_scalar(hg.forward());
        dchars += sent.size() - 1;
      }
      if (dloss < best) {
        best = dloss;
        ofstream out(fname);
        boost::archive::text_oarchive oa(out);
        oa << model;
      }
      cerr << "\n***DEV [epoch=" << (lines / (double)training.size()) << "] E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
    }
  }
  delete sgd;
}

<|endoftext|>


<commit_before>//
// emoji.hpp
// *********
//
// Copyright (c) 2020 Sharon Fox (sharon at xandium dot io)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/snowflake.hpp"
#include <nlohmann/json.hpp>

namespace aegis
{

namespace gateway
{

namespace objects
{

struct emoji;

/// \cond TEMPLATES
void from_json(const nlohmann::json& j, emoji& m);
void to_json(nlohmann::json& j, const emoji& m);
/// \endcond

/// Discord Emoji Object
struct emoji
{
    emoji(const std::string& _json, aegis::core* bot) noexcept
    {
        from_json(nlohmann::json::parse(_json), *this);
    }

    emoji(const nlohmann::json& _json, aegis::core* bot) noexcept
    {
        from_json(_json, *this);
    }

    emoji(aegis::core* bot) noexcept {}

    emoji() noexcept {}

    /// Formats the emoji for adding to a message
    /**
     * @returns string of formatted emoji
     */
    std::string format() const noexcept
    {
        return id ? fmt::format("<{}:{}:{}>", animated ? "a" : "", name, id) : name;
    }

    snowflake id; /**< Emoji ID */
    std::string name; /**< Emoji Name */
    std::vector<snowflake> roles; /**< Roles this emoji is whitelisted to */
    snowflake user; /**< User that created this emoji */
    bool require_colons = false; /**< Whether this emoji must be wrapped in colons */
    bool managed = false; /**< Whether this emoji is managed */
    bool animated = false; /**< Whether this emoji is animated */
};

/// \cond TEMPLATES
inline void from_json(const nlohmann::json& j, emoji& m)
{
    m.id = j["id"];
    if (j.count("name") && !j["name"].is_null())
        m.name = j["name"].get<std::string>();
    if (j.count("user") && !j["user"].is_null())
        m.user = j["user"]["id"];
    if (j.count("require_colons") && !j["require_colons"].is_null())
        m.require_colons = j["require_colons"];
    if (j.count("managed") && !j["managed"].is_null())
        m.managed = j["managed"];
    if (j.count("animated") && !j["animated"].is_null())
        m.animated = j["animated"];
    if (j.count("roles") && !j["roles"].is_null())
        for (const auto & i : j["roles"])
            m.roles.push_back(i);
}

inline void to_json(nlohmann::json& j, const emoji& m)
{
    j["id"] = std::to_string(m.id);
    j["name"] = m.name;
    j["user"] = m.user;
    j["require_colons"] = m.require_colons;
    j["managed"] = m.managed;
    j["animated"] = m.animated;
    for (const auto & i : m.roles)
        j["roles"].push_back(i);
}
/// \endcond

}

}

}
<commit_msg>Add reaction formatting method to emojis<commit_after>//
// emoji.hpp
// *********
//
// Copyright (c) 2020 Sharon Fox (sharon at xandium dot io)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/config.hpp"
#include "aegis/snowflake.hpp"
#include <nlohmann/json.hpp>

namespace aegis
{

namespace gateway
{

namespace objects
{

struct emoji;

/// \cond TEMPLATES
void from_json(const nlohmann::json& j, emoji& m);
void to_json(nlohmann::json& j, const emoji& m);
/// \endcond

/// Discord Emoji Object
struct emoji
{
    emoji(const std::string& _json, aegis::core* bot) noexcept
    {
        from_json(nlohmann::json::parse(_json), *this);
    }

    emoji(const nlohmann::json& _json, aegis::core* bot) noexcept
    {
        from_json(_json, *this);
    }

    emoji(aegis::core* bot) noexcept {}

    emoji() noexcept {}

    /// Formats the emoji for adding to a message
    /**
     * @returns string of formatted emoji
     */
    std::string format() const noexcept
    {
        return id ? fmt::format("<{}:{}:{}>", animated ? "a" : "", name, id) : name;
    }

    /// Formats the emoji for use as a reaction
    /**
    * @returns string of reaction-formatted emoji
    */
    std::string reaction() const noexcept
    {
        return id ? fmt::format("{}:{}", name, id) : name;
    }

    snowflake id; /**< Emoji ID */
    std::string name; /**< Emoji Name */
    std::vector<snowflake> roles; /**< Roles this emoji is whitelisted to */
    snowflake user; /**< User that created this emoji */
    bool require_colons = false; /**< Whether this emoji must be wrapped in colons */
    bool managed = false; /**< Whether this emoji is managed */
    bool animated = false; /**< Whether this emoji is animated */
};

/// \cond TEMPLATES
inline void from_json(const nlohmann::json& j, emoji& m)
{
    m.id = j["id"];
    if (j.count("name") && !j["name"].is_null())
        m.name = j["name"].get<std::string>();
    if (j.count("user") && !j["user"].is_null())
        m.user = j["user"]["id"];
    if (j.count("require_colons") && !j["require_colons"].is_null())
        m.require_colons = j["require_colons"];
    if (j.count("managed") && !j["managed"].is_null())
        m.managed = j["managed"];
    if (j.count("animated") && !j["animated"].is_null())
        m.animated = j["animated"];
    if (j.count("roles") && !j["roles"].is_null())
        for (const auto & i : j["roles"])
            m.roles.push_back(i);
}

inline void to_json(nlohmann::json& j, const emoji& m)
{
    j["id"] = std::to_string(m.id);
    j["name"] = m.name;
    j["user"] = m.user;
    j["require_colons"] = m.require_colons;
    j["managed"] = m.managed;
    j["animated"] = m.animated;
    for (const auto & i : m.roles)
        j["roles"].push_back(i);
}
/// \endcond

}

}

}
<|endoftext|>


<commit_before><commit_msg>fix windows build(2)<commit_after><|endoftext|>