<commit_before>
#include "nui.h"
#include "nuiDrawerView.h"

static const float SPRING_TOLERANCE = 0.0000000005f;
static const float STIFFNESS = .3f;
static const float PULL_COEF = 4;
static const float MOVE_TOLERANCE = 8;

nuiDrawerView::nuiDrawerView() :
mpLeft(nullptr), mpMain(nullptr), mpRight(nullptr), mOffset(0), mTouched(false), mMoving(false), mOriginalOffset(0), mTargetOffset(0), mEventSink(this)
{
  if (SetObjectClass("nuiDrawerView"))
  {
    // Init attributes:
  }

  nuiAnimation::AcquireTimer();
}

nuiDrawerView::~nuiDrawerView()
{
  nuiAnimation::ReleaseTimer();
}

bool nuiDrawerView::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  //NGL_OUT("Set Rect with mOffset %f\n", mOffset);
  if (mpLeft)
  {
    nuiRect r(MIN(mpLeft->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MIN(0, mOffset - r.GetWidth()), 0);
    mpLeft->SetLayout(r);
  }

  if (mpMain)
  {
    nuiRect r(rRect.Size());
    r.Move(mOffset, 0);
    mpMain->SetLayout(r);
  }

  if (mpRight)
  {
    nuiRect r(MIN(mpRight->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MAX(mOffset + rRect.GetWidth(), rRect.GetWidth() - r.GetWidth()), 0);
    mpRight->SetLayout(r);
  }
}

nuiRect nuiDrawerView::CalcIdealSize()
{
  return mpMain ? mpMain->GetIdealRect() : nuiRect();
}

bool nuiDrawerView::AddChild(nuiWidgetPtr pWidget)
{
  if (pWidget->GetProperty("Drawer").Compare("left", false) == 0)
  {
    if (mpLeft)
      DelChild(mpLeft);
    mpLeft = pWidget;
  }
  else if (pWidget->GetProperty("Drawer").Compare("right", false) == 0)
  {
    if (mpRight)
      DelChild(mpRight);
    mpRight = pWidget;
  }
  else
  {
    if (mpMain)
      DelChild(mpMain);
    mpMain = pWidget;
  }
  nuiSimpleContainer::AddChild(pWidget);
}

bool nuiDrawerView::DelChild(nuiWidgetPtr pWidget)
{
  if (pWidget == mpLeft)
    mpLeft = NULL;
  if (pWidget == mpRight)
    mpRight = NULL;
  if (pWidget == mpMain)
    mpMain = NULL;
  nuiSimpleContainer::DelChild(pWidget);
}

void nuiDrawerView::SetLeft(nuiWidgetPtr pWidget)
{
  if (mpLeft)
    DelChild(mpLeft);
  if (pWidget)
    AddChild(pWidget);
  mpLeft = pWidget;
}

void nuiDrawerView::SetMain(nuiWidgetPtr pWidget)
{
  if (mpMain)
    DelChild(mpMain);
  if (pWidget)
    AddChild(pWidget);
  mpMain = pWidget;
}

void nuiDrawerView::SetRight(nuiWidgetPtr pWidget)
{
  if (mpRight)
    DelChild(mpRight);
  if (pWidget)
    AddChild(pWidget);
  mpRight = pWidget;
}

nuiWidgetPtr nuiDrawerView::GetLeft()
{
  return mpLeft;
}

nuiWidgetPtr nuiDrawerView::GetMain()
{
  return mpMain;
}

nuiWidgetPtr nuiDrawerView::GetRight()
{
  return mpRight;
}

bool nuiDrawerView::PreMouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mTouch = rInfo;
    mTouched = true;
    mOriginalOffset = mOffset;
   //NGL_OUT("PreMouseClicked mOriginalOffset = %f\n", mOriginalOffset);
  }
  return false;
}

bool nuiDrawerView::PreMouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    if (mTouched && !mMoving && mOffset != 0)
    {
      if ((mOffset < 0 && rInfo.X < mRect.GetWidth() + mOffset) || (mOffset > 0 && rInfo.X > mOffset))
      {
        if (mpMain)
        {
          mpMain->DispatchMouseCanceled(rInfo);
        }
        mTouched = false;

        mTargetOffset = 0;
        mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);

        return true;
      }
    }
    mTouched = false;
  }
  return false;
}

bool nuiDrawerView::PreMouseMoved(const nglMouseInfo& rInfo)
{
  if (mTouched && !mMoving)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      if (StealMouseEvent(rInfo))
      {
        mTouched = false;
        mMoving = true;
        return true;
      }
    }
  }
  return false;
}

bool nuiDrawerView::MouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mMoving = false;
    mTouched = false;

    mTouch = rInfo;
    mOriginalOffset = mOffset;

    SetSelected(true);
    // Stop events, just in case...
    mEventSink.DisconnectAll();
  }
  return false;
}

void nuiDrawerView::ReleaseTouch()
{
  mMoving = false;
  mTouched = false;

  if (mOffset < 0)
  {
    // We should we go?
    float width = mpRight->GetIdealRect().GetWidth();
    if (-mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = -width;
    }
  }
  else if (mOffset > 0)
  {
    // We should we go?
    float width = mpLeft->GetIdealRect().GetWidth();
    if (mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = width;
    }
  }
  else
  {
    mTargetOffset = 0;
  }

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::MouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    ReleaseTouch();
    SetSelected(false);
  }
  return false;
}

bool nuiDrawerView::MouseMoved(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    float dx = mTouch.X - rInfo.X;
    mOffset = mOriginalOffset -dx;
    if (mOffset < 0)
    {
      if (!mpRight)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpRight->GetIdealRect().GetWidth();
        if (mOffset < -width)
        {
          // Compute the position with the
          float diff = -mOffset - width ;
          mOffset = -width - PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }
    else
    {
      if (!mpLeft)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpLeft->GetIdealRect().GetWidth();
        if (mOffset > width)
        {
          // Compute the position with the
          float diff = mOffset - width ;
          mOffset = width + PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }

    //NGL_OUT("Mouse moved, new offset = %f\n", mOffset);
    UpdateLayout();
    return true;
  }

  if (mTouched)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      mTouched = false;
      mMoving = true;
    }
  }
  return false;
}

bool nuiDrawerView::MouseCanceled(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    ReleaseTouch();
  }
  SetSelected(false);
  mTouched = false;
  mMoving = false;
  return false;
}

void nuiDrawerView::OnAnimateDrawer(const nuiEvent &rEvent)
{
  float diff = mTargetOffset - mOffset;
  mOffset += diff / 8;

  //NGL_OUT(".");
  diff = mTargetOffset - mOffset;
  if (fabs(diff) < 1.0)
  {
    //NGL_OUT("nuiDrawerView Offset Realease Done\n");
    mOffset = mTargetOffset;
    //NGL_OUT("!!!!!!!! Anim end mOffset = %f\n", mOffset);
    mEventSink.DisconnectAll();
  }

  mOriginalOffset = mOffset;
  UpdateLayout();
}
<commit_msg>cosmetics<commit_after>
#include "nui.h"
#include "nuiDrawerView.h"

static const float SPRING_TOLERANCE = 0.0000000005f;
static const float STIFFNESS = .3f;
static const float PULL_COEF = 4;
static const float MOVE_TOLERANCE = 8;

nuiDrawerView::nuiDrawerView() :
mpLeft(nullptr), mpMain(nullptr), mpRight(nullptr), mOffset(0), mTouched(false), mMoving(false), mOriginalOffset(0), mTargetOffset(0), mEventSink(this)
{
  if (SetObjectClass("nuiDrawerView"))
  {
    // Init attributes:
  }

  nuiAnimation::AcquireTimer();
}

nuiDrawerView::~nuiDrawerView()
{
  nuiAnimation::ReleaseTimer();
}

bool nuiDrawerView::SetRect(const nuiRect& rRect)
{
  nuiWidget::SetRect(rRect);
  //NGL_OUT("Set Rect with mOffset %f\n", mOffset);
  if (mpLeft)
  {
    nuiRect r(MIN(mpLeft->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MIN(0, mOffset - r.GetWidth()), 0);
    mpLeft->SetLayout(r);
  }

  if (mpMain)
  {
    nuiRect r(rRect.Size());
    r.Move(mOffset, 0);
    mpMain->SetLayout(r);
  }

  if (mpRight)
  {
    nuiRect r(MIN(mpRight->GetIdealRect().GetWidth(), rRect.GetWidth()), rRect.GetHeight());
    r.Move(MAX(mOffset + rRect.GetWidth(), rRect.GetWidth() - r.GetWidth()), 0);
    mpRight->SetLayout(r);
  }
}

nuiRect nuiDrawerView::CalcIdealSize()
{
  return mpMain ? mpMain->GetIdealRect() : nuiRect();
}

bool nuiDrawerView::AddChild(nuiWidgetPtr pWidget)
{
  if (pWidget->GetProperty("Drawer").Compare("left", false) == 0)
  {
    if (mpLeft)
      DelChild(mpLeft);
    mpLeft = pWidget;
  }
  else if (pWidget->GetProperty("Drawer").Compare("right", false) == 0)
  {
    if (mpRight)
      DelChild(mpRight);
    mpRight = pWidget;
  }
  else
  {
    if (mpMain)
      DelChild(mpMain);
    mpMain = pWidget;
  }
  nuiSimpleContainer::AddChild(pWidget);
}

bool nuiDrawerView::DelChild(nuiWidgetPtr pWidget)
{
  if (pWidget == mpLeft)
    mpLeft = NULL;
  if (pWidget == mpRight)
    mpRight = NULL;
  if (pWidget == mpMain)
    mpMain = NULL;
  nuiSimpleContainer::DelChild(pWidget);
}

void nuiDrawerView::SetLeft(nuiWidgetPtr pWidget)
{
  if (mpLeft)
    DelChild(mpLeft);
  if (pWidget)
    AddChild(pWidget);
  mpLeft = pWidget;
}

void nuiDrawerView::SetMain(nuiWidgetPtr pWidget)
{
  if (mpMain)
    DelChild(mpMain);
  if (pWidget)
    AddChild(pWidget);
  mpMain = pWidget;
}

void nuiDrawerView::SetRight(nuiWidgetPtr pWidget)
{
  if (mpRight)
    DelChild(mpRight);
  if (pWidget)
    AddChild(pWidget);
  mpRight = pWidget;
}

nuiWidgetPtr nuiDrawerView::GetLeft()
{
  return mpLeft;
}

nuiWidgetPtr nuiDrawerView::GetMain()
{
  return mpMain;
}

nuiWidgetPtr nuiDrawerView::GetRight()
{
  return mpRight;
}

bool nuiDrawerView::PreMouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mTouch = rInfo;
    mTouched = true;
    mOriginalOffset = mOffset;
   //NGL_OUT("PreMouseClicked mOriginalOffset = %f\n", mOriginalOffset);
  }
  return false;
}

bool nuiDrawerView::PreMouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    if (mTouched && !mMoving && mOffset != 0)
    {
      if ((mOffset < 0 && rInfo.X < mRect.GetWidth() + mOffset) || (mOffset > 0 && rInfo.X > mOffset))
      {
        if (mpMain)
        {
          mpMain->DispatchMouseCanceled(rInfo);
        }
        mTouched = false;

        mTargetOffset = 0;
        mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);

        return true;
      }
    }
    mTouched = false;
  }
  return false;
}

bool nuiDrawerView::PreMouseMoved(const nglMouseInfo& rInfo)
{
  if (mTouched && !mMoving)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      if (StealMouseEvent(rInfo))
      {
        mTouched = false;
        mMoving = true;
        return true;
      }
    }
  }
  return false;
}

bool nuiDrawerView::MouseClicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    mMoving = false;
    mTouched = false;

    mTouch = rInfo;
    mOriginalOffset = mOffset;

    SetSelected(true);
    // Stop events, just in case...
    mEventSink.DisconnectAll();
  }
  return false;
}

void nuiDrawerView::ReleaseTouch()
{
  mMoving = false;
  mTouched = false;

  if (mOffset < 0)
  {
    // We should we go?
    float width = mpRight->GetIdealRect().GetWidth();
    if (-mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = -width;
    }
  }
  else if (mOffset > 0)
  {
    // We should we go?
    float width = mpLeft->GetIdealRect().GetWidth();
    if (mOffset < width * 0.5)
    {
      // We're less than half way though, so we go back to our original position:
      mTargetOffset = 0;
    }
    else
    {
      mTargetOffset = width;
    }
  }
  else
  {
    mTargetOffset = 0;
  }

  if (mOffset != mTargetOffset)
  {
    mEventSink.Connect(nuiAnimation::GetTimer()->Tick, &nuiDrawerView::OnAnimateDrawer);
  }

  UpdateLayout();
}

bool nuiDrawerView::MouseUnclicked(const nglMouseInfo& rInfo)
{
  if (rInfo.Buttons & nglMouseInfo::ButtonLeft)
  {
    ReleaseTouch();
    SetSelected(false);
  }
  return false;
}

bool nuiDrawerView::MouseMoved(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    float dx = mTouch.X - rInfo.X;
    mOffset = mOriginalOffset -dx;
    if (mOffset < 0)
    {
      if (!mpRight)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpRight->GetIdealRect().GetWidth();
        if (mOffset < -width)
        {
          // Compute the position with the
          float diff = -mOffset - width ;
          mOffset = -width - PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }
    else
    {
      if (!mpLeft)
      {
        mOffset = 0;
      }
      else
      {
        float width = mpLeft->GetIdealRect().GetWidth();
        if (mOffset > width)
        {
          // Compute the position with the
          float diff = mOffset - width ;
          mOffset = width + PULL_COEF * sqrt(diff);
          //NGL_OUT("Diff : %f\n", diff);
        }
      }
    }

    //NGL_OUT("Mouse moved, new offset = %f\n", mOffset);
    UpdateLayout();
    return true;
  }

  if (mTouched)
  {
    float x = 0;
    x = mTouch.X - rInfo.X;
    float dist = fabs(x);

    if (dist > MOVE_TOLERANCE)
    {
      //NGL_OUT("nuiDrawerView Preempting mouse from existing grabber!\n");
      NGL_ASSERT(GetTopLevel());

      mTouched = false;
      mMoving = true;
    }
  }
  return false;
}

bool nuiDrawerView::MouseCanceled(const nglMouseInfo& rInfo)
{
  if (mMoving)
  {
    ReleaseTouch();
  }
  SetSelected(false);
  mTouched = false;
  mMoving = false;
  return false;
}

void nuiDrawerView::OnAnimateDrawer(const nuiEvent &rEvent)
{
  float diff = mTargetOffset - mOffset;
  mOffset += diff / 8;

  //NGL_OUT(".");
  diff = mTargetOffset - mOffset;
  if (fabs(diff) < 1.0)
  {
    //NGL_OUT("nuiDrawerView Offset Realease Done\n");
    mOffset = mTargetOffset;
    //NGL_OUT("!!!!!!!! Anim end mOffset = %f\n", mOffset);
    mEventSink.DisconnectAll();
  }

  mOriginalOffset = mOffset;
  UpdateLayout();
}
<|endoftext|>


<commit_before><commit_msg>Fixed a comment.<commit_after><|endoftext|>


<commit_before><commit_msg>cache calls to size<commit_after><|endoftext|>


<commit_before><commit_msg>fdo#66646: fix paste special with empty cells<commit_after><|endoftext|>


<commit_before>// ircbot2
// The MIT License(MIT)
//
// Copyright(c) 2015 Abricot Soinou <abricot.soinou@gmail.com>
//
// 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.

#include "script_manager.h"

#include "logger.h"
#include "utils.h"

// Constructor
ScriptManager::ScriptManager() : scripts_()
{

}

// Destructor
ScriptManager::~ScriptManager()
{

}

// Loads the script manager with the given server
void ScriptManager::load(Server* server)
{
    // Get the list of files in the scripts folder
    std::vector<std::string> scripts = Utils::get_files_from_folder("scripts", ".lua");

    // For each file
    for (auto i = scripts.begin(); i != scripts.end(); i++)
    {
        // Create a new script with this file
        Script* script = new Script(*i);

        // Load this script
        script->load(server);

        // Add this script to our list of scripts
        scripts_.push_back(std::unique_ptr<Script>(script));
    }
}

// Called when a command is triggered
void ScriptManager::on_command(const std::string& sender, const std::string& command_string, const std::vector<std::string>& arguments)
{
    try
    {
        // For each script
        for (auto i = scripts_.begin(); i != scripts_.end(); i++)
            // If the script is a command script and his command string matches our command string
            if ((*i)->type() == Script::Type::Command && (*i)->command_string() == command_string)
                // If we have the right number of arguments
                if (arguments.size() >= (*i)->min_arguments() && arguments.size() <= (*i)->max_arguments())
                    // Call him
                    (*i)->on_command(sender, command_string, arguments);
    }
    // Catch lua exceptions
    catch (std::runtime_error e)
    {
        // Log them
        Log.error(e.what());
        fprintf(stderr, e.what());
    }
}

// Called when a message is sent
void ScriptManager::on_message(const std::string& sender, const std::string& message)
{
    try
    {
        // For each script
        for (auto i = scripts_.begin(); i != scripts_.end(); i++)
            // If the script is a message script
            if ((*i)->type() == Script::Type::Message)
                // Call him
                (*i)->on_message(sender, message);
    }
    // Catch lua exceptions
    catch (std::runtime_error e)
    {
        // Log them
        Log.error(e.what());
        fprintf(stderr, e.what());
    }
}<commit_msg>Forgot format on lua errors<commit_after>// ircbot2
// The MIT License(MIT)
//
// Copyright(c) 2015 Abricot Soinou <abricot.soinou@gmail.com>
//
// 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.

#include "script_manager.h"

#include "logger.h"
#include "utils.h"

// Constructor
ScriptManager::ScriptManager() : scripts_()
{

}

// Destructor
ScriptManager::~ScriptManager()
{

}

// Loads the script manager with the given server
void ScriptManager::load(Server* server)
{
    // Get the list of files in the scripts folder
    std::vector<std::string> scripts = Utils::get_files_from_folder("scripts", ".lua");

    // For each file
    for (auto i = scripts.begin(); i != scripts.end(); i++)
    {
        // Create a new script with this file
        Script* script = new Script(*i);

        // Load this script
        script->load(server);

        // Add this script to our list of scripts
        scripts_.push_back(std::unique_ptr<Script>(script));
    }
}

// Called when a command is triggered
void ScriptManager::on_command(const std::string& sender, const std::string& command_string, const std::vector<std::string>& arguments)
{
    try
    {
        // For each script
        for (auto i = scripts_.begin(); i != scripts_.end(); i++)
            // If the script is a command script and his command string matches our command string
            if ((*i)->type() == Script::Type::Command && (*i)->command_string() == command_string)
                // If we have the right number of arguments
                if (arguments.size() >= (*i)->min_arguments() && arguments.size() <= (*i)->max_arguments())
                    // Call him
                    (*i)->on_command(sender, command_string, arguments);
    }
    // Catch lua exceptions
    catch (std::runtime_error e)
    {
        // Log them
        Log.error(e.what());
        fprintf(stderr, "Lua Error: %s\n", e.what());
    }
}

// Called when a message is sent
void ScriptManager::on_message(const std::string& sender, const std::string& message)
{
    try
    {
        // For each script
        for (auto i = scripts_.begin(); i != scripts_.end(); i++)
            // If the script is a message script
            if ((*i)->type() == Script::Type::Message)
                // Call him
                (*i)->on_message(sender, message);
    }
    // Catch lua exceptions
    catch (std::runtime_error e)
    {
        // Log them
        Log.error(e.what());
        fprintf(stderr, "Lua Error: %s\n", e.what());
    }
}
<|endoftext|>


<commit_before><commit_msg>Use the source dimension name when searching for a dimension.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "opengldetect.h"

// This needs to be first because if it is not GL/glew.h
// complains about being included after gl.h
// clang-format off
#include "OpenGl.h" // IWYU pragma: keep
// clang-format on

#include <absl/strings/numbers.h>
#include <absl/strings/str_split.h>

#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QSurfaceFormat>

namespace orbit_qt {
namespace {

// Must have created an OpenGl context before calling this.
std::optional<OpenGlVersion> GetOpenGlVersionViaDirectCall() {
  std::string gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
  std::vector<std::string> version_tokenized = absl::StrSplit(gl_version, '.');

  if (version_tokenized.size() < 2) {
    return std::nullopt;
  }

  int major_version;
  if (!absl::SimpleAtoi(version_tokenized[0], &major_version)) {
    return std::nullopt;
  }
  int minor_version;
  if (!absl::SimpleAtoi(version_tokenized[1], &minor_version)) {
    return std::nullopt;
  }
  return OpenGlVersion{major_version, minor_version};
}

std::optional<OpenGlVersion> ComputeMinimumVersion(std::optional<OpenGlVersion> version_a,
                                                   std::optional<OpenGlVersion> version_b) {
  if (!version_a || !version_b) {
    return std::nullopt;
  }
  if (version_a.value().major < version_b.value().major) {
    return version_a;
  }
  if (version_b.value().major < version_a.value().major) {
    return version_b;
  }
  if (version_a.value().minor < version_b.value().minor) {
    return version_a;
  }
  return version_b;
}
}  // namespace

// Detects the supported version of Desktop OpenGL by (1) requesting the most
// recent version of OpenGL and checking what the system could provide and (2)
// calling glGetString(GL_VERSION). The versions obtained via (1) and (2) are
// compared and the smaller of the two is returned.
// OpenGL ES is automatically ignored.
std::optional<OpenGlVersion> DetectOpenGlVersion() {
  QSurfaceFormat format{};
  format.setRenderableType(QSurfaceFormat::OpenGL);
  format.setVersion(4, 6);

  QOffscreenSurface surface{};
  surface.setFormat(format);
  surface.create();

  if (!surface.isValid()) {
    return std::nullopt;
  }

  QOpenGLContext gl_context{};
  gl_context.setFormat(format);
  gl_context.create();
  gl_context.makeCurrent(&surface);

  // We are trying to detect Desktop OpenGL. So if Qt falls back to OpenGL ES,
  // Desktop OpenGL will not be available.
  if (!gl_context.isValid() || gl_context.isOpenGLES()) {
    return std::nullopt;
  }

  std::optional<OpenGlVersion> gl_version_direct = GetOpenGlVersionViaDirectCall();
  if (!gl_version_direct) {
    return std::nullopt;
  }
  OpenGlVersion qt_gl_version{surface.format().majorVersion(), surface.format().minorVersion()};

  return ComputeMinimumVersion(gl_version_direct, qt_gl_version);
}
}  // namespace orbit_qt<commit_msg>Fix parsing of OpenGL version numbers<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "opengldetect.h"

// This needs to be first because if it is not GL/glew.h
// complains about being included after gl.h
// clang-format off
#include "OpenGl.h" // IWYU pragma: keep
// clang-format on

#include <absl/strings/numbers.h>
#include <absl/strings/str_split.h>

#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QSurfaceFormat>

namespace orbit_qt {
namespace {

// Must have created an OpenGl context before calling this. Assumes that both
// major and minor versions of the string are single digits.
std::optional<OpenGlVersion> GetOpenGlVersionViaDirectCall() {
  std::string gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
  if (gl_version.size() < 3) {
    return std::nullopt;
  }
  int major_version;
  if (!absl::SimpleAtoi(gl_version.substr(0, 1), &major_version)) {
    return std::nullopt;
  }
  int minor_version;
  if (!absl::SimpleAtoi(gl_version.substr(2, 1), &minor_version)) {
    return std::nullopt;
  }
  return OpenGlVersion{major_version, minor_version};
}

std::optional<OpenGlVersion> ComputeMinimumVersion(std::optional<OpenGlVersion> version_a,
                                                   std::optional<OpenGlVersion> version_b) {
  if (!version_a || !version_b) {
    return std::nullopt;
  }
  if (version_a.value().major < version_b.value().major) {
    return version_a;
  }
  if (version_b.value().major < version_a.value().major) {
    return version_b;
  }
  if (version_a.value().minor < version_b.value().minor) {
    return version_a;
  }
  return version_b;
}
}  // namespace

// Detects the supported version of Desktop OpenGL by (1) requesting the most
// recent version of OpenGL and checking what the system could provide and (2)
// calling glGetString(GL_VERSION). The versions obtained via (1) and (2) are
// compared and the smaller of the two is returned.
// OpenGL ES is automatically ignored.
std::optional<OpenGlVersion> DetectOpenGlVersion() {
  QSurfaceFormat format{};
  format.setRenderableType(QSurfaceFormat::OpenGL);
  format.setVersion(4, 6);

  QOffscreenSurface surface{};
  surface.setFormat(format);
  surface.create();

  if (!surface.isValid()) {
    return std::nullopt;
  }

  QOpenGLContext gl_context{};
  gl_context.setFormat(format);
  gl_context.create();
  gl_context.makeCurrent(&surface);

  // We are trying to detect Desktop OpenGL. So if Qt falls back to OpenGL ES,
  // Desktop OpenGL will not be available.
  if (!gl_context.isValid() || gl_context.isOpenGLES()) {
    return std::nullopt;
  }

  std::optional<OpenGlVersion> gl_version_direct = GetOpenGlVersionViaDirectCall();
  if (!gl_version_direct) {
    return std::nullopt;
  }
  OpenGlVersion qt_gl_version{surface.format().majorVersion(), surface.format().minorVersion()};

  return ComputeMinimumVersion(gl_version_direct, qt_gl_version);
}
}  // namespace orbit_qt<|endoftext|>


<commit_before>/**
 * @file train.cc
 *
 * This file contains the program to estimate Hidden Markov Model parameter
 * using training sequences.
 *
 * It use two algorithm: Baum-Welch (EM) and Viterbi
 *
 * Usage:
 *   train --type=TYPE --profile=PROFILE --seqfile=FILE [OPTIONS]
 * See the usage() function for complete option list
 */

#include <fastlib/fastlib.h>
#include "support.h"
#include "discreteHMM.h"
#include "gaussianHMM.h"
#include "mixgaussHMM.h"
#include "mixtureDST.h"
#include "hmm_documentation.h"

using namespace hmm_support;

success_t train_baumwelch();
success_t train_viterbi();
void usage();

const fx_entry_doc hmm_train_main_entries[] = {
  {"input_file", FX_REQUIRED, FX_STR, NULL,
   "Input file containing data sequences to train on.\n"},
  {"guess_file", FX_PARAM, FX_STR, NULL,
   "File containing guess of HMM model profile (.hmm)\n"},
  {"output_file", FX_PARAM, FX_STR, NULL,
   "Output file containing trained HMM profile (default output.<type>.hmm)\n"},
  {"type", FX_REQUIRED, FX_STR, NULL,
   "HMM type: discrete | gaussian | mixture\n"},
  {"algorithm", FX_PARAM, FX_STR, NULL,
   "Training algorithm: baumwelch | viterbi (default baumwelch)\n"},
  {"num_states", FX_PARAM, FX_INT, NULL,
   "If no guess profile is specified, at least provide the number of states\n"},
  {"max_iter", FX_PARAM, FX_INT, NULL,
   "Maximum number of iterations (default 500)\n"},
  {"tolerance", FX_PARAM, FX_DOUBLE, NULL,
   "Error tolerance on log-likelihood as a stopping criteria (default 0.001)\n"},
  FX_ENTRY_DOC_DONE
};

const fx_submodule_doc hmm_train_submod_entries[] = {
  {"formats", &hmm_format_doc,
  "Documentation for file formats used by this program and other MLPACK HMM tools\n"},
  FX_SUBMODULE_DOC_DONE
};

const fx_module_doc hmm_train_main_doc = {
  hmm_train_main_entries, hmm_train_submod_entries,
  "The hmm_train utility is for training HMMs from data sequences. Given an\n"
  "input file of data sequences, and optionally a file containing a guess of\n"
  "the HMM profile (or a parameter specifying the number of states), the program\n"
  "will use the specified training algorithm (Viterbi or Baum-Welch, default\n"
  "Baum-Welch) to train the HMM until the log-likelihood error reaches the given\n"
  "value (default 0.001).\n"
  "\n"
  "It is important to note that if the guess file is not specified, the number\n"
  "of states must be specified.  Additionally, a guess file must be specified\n"
  "if the HMM type is 'mixture'.\n"
  "\n"
  "See the documentation in the 'formats' submodule (--help=formats) for more\n"
  "information on the file formats that this program uses.\n"
};

int main(int argc, char* argv[]) {
  fx_init(argc, argv, &hmm_train_main_doc);
  success_t s = SUCCESS_PASS;
  if (fx_param_exists(NULL, "type")) {
    const char* algorithm = fx_param_str(NULL, "algorithm", "baumwelch");
    if (strcmp(algorithm, "baumwelch") == 0)
      s = train_baumwelch();
    else if (strcmp(algorithm, "viterbi") == 0)
      s = train_viterbi();
    else {
      FATAL("Unrecognized training algorithm: must be 'baumwelch' or 'viterbi'.\n");
      s = SUCCESS_FAIL;
    }
  }
  else {
    FATAL("Unrecognized HMM type; must be 'discrete', 'gaussian', or 'mixture'.\n");
    s = SUCCESS_FAIL;
  }

  fx_done(NULL);
}

success_t train_baumwelch_discrete();
success_t train_baumwelch_gaussian();
success_t train_baumwelch_mixture();

success_t train_baumwelch() {
  const char* type = fx_param_str_req(NULL, "type");
  if (strcmp(type, "discrete")==0)
    return train_baumwelch_discrete();
  else if (strcmp(type, "gaussian")==0)
    return train_baumwelch_gaussian();
  else if (strcmp(type, "mixture")==0)
    return train_baumwelch_mixture();

  return SUCCESS_FAIL;
}

success_t train_viterbi_discrete();
success_t train_viterbi_gaussian();
success_t train_viterbi_mixture();

success_t train_viterbi() {
  const char* type = fx_param_str_req(NULL, "type");
  if (strcmp(type, "discrete")==0)
    return train_viterbi_discrete();
  else if (strcmp(type, "gaussian")==0)
    return train_viterbi_gaussian();
  else if (strcmp(type, "mixture")==0)
    return train_viterbi_mixture();

  return SUCCESS_FAIL;
}

success_t train_baumwelch_mixture() {
  MixtureofGaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.mix.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else {
    hmm.Init();
    FATAL("Automatic initialization not supported for mixture training.");
    return SUCCESS_FAIL;
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_baumwelch_gaussian() {
  GaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.gauss.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generating HMM parameters: %d states...", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_baumwelch_discrete() {
  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.dis.hmm");

  ArrayList<Vector> seqs;
  load_vector_list(seqin, &seqs);

  DiscreteHMM hmm;

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading HMM parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise randomly initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Randomly generating parameters: %d states...", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_mixture() {
  MixtureofGaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.mix.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading parameters from guess file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else {
    hmm.Init();
    FATAL("Automatic initialization not supported for mixture training.");
    return SUCCESS_FAIL;
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_gaussian() {
  GaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.gauss.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generating parameters with %d states\n", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_discrete() {
  DiscreteHMM hmm;
  ArrayList<Vector> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_file", "output.dis.hmm");

  load_vector_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_file")) { // guessed parameters in a file
    ArrayList<Matrix> matlst;
    const char* guess = fx_param_str_req(NULL, "guess_file");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise randomly initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generate parameters with %d states\n", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}
<commit_msg>Change some parameter names to indicate where model files are required<commit_after>/**
 * @file train.cc
 *
 * This file contains the program to estimate Hidden Markov Model parameter
 * using training sequences.
 *
 * It use two algorithm: Baum-Welch (EM) and Viterbi
 *
 * Usage:
 *   train --type=TYPE --profile=PROFILE --seqfile=FILE [OPTIONS]
 * See the usage() function for complete option list
 */

#include <fastlib/fastlib.h>
#include "support.h"
#include "discreteHMM.h"
#include "gaussianHMM.h"
#include "mixgaussHMM.h"
#include "mixtureDST.h"
#include "hmm_documentation.h"

using namespace hmm_support;

success_t train_baumwelch();
success_t train_viterbi();
void usage();

const fx_entry_doc hmm_train_main_entries[] = {
  {"input_file", FX_REQUIRED, FX_STR, NULL,
   "Input file containing data sequences to train on.\n"},
  {"guess_model", FX_PARAM, FX_STR, NULL,
   "File containing guess of HMM model profile (.hmm)\n"},
  {"output_model", FX_PARAM, FX_STR, NULL,
   "Output file containing trained HMM profile (default output.<type>.hmm)\n"},
  {"type", FX_REQUIRED, FX_STR, NULL,
   "HMM type: discrete | gaussian | mixture\n"},
  {"algorithm", FX_PARAM, FX_STR, NULL,
   "Training algorithm: baumwelch | viterbi (default baumwelch)\n"},
  {"num_states", FX_PARAM, FX_INT, NULL,
   "If no guess profile is specified, at least provide the number of states\n"},
  {"max_iter", FX_PARAM, FX_INT, NULL,
   "Maximum number of iterations (default 500)\n"},
  {"tolerance", FX_PARAM, FX_DOUBLE, NULL,
   "Error tolerance on log-likelihood as a stopping criteria (default 0.001)\n"},
  FX_ENTRY_DOC_DONE
};

const fx_submodule_doc hmm_train_submod_entries[] = {
  {"formats", &hmm_format_doc,
  "Documentation for file formats used by this program and other MLPACK HMM tools\n"},
  FX_SUBMODULE_DOC_DONE
};

const fx_module_doc hmm_train_main_doc = {
  hmm_train_main_entries, hmm_train_submod_entries,
  "The hmm_train utility is for training HMMs from data sequences. Given an\n"
  "input file of data sequences, and optionally a file containing a guess of\n"
  "the HMM profile (or a parameter specifying the number of states), the program\n"
  "will use the specified training algorithm (Viterbi or Baum-Welch, default\n"
  "Baum-Welch) to train the HMM until the log-likelihood error reaches the given\n"
  "value (default 0.001).\n"
  "\n"
  "It is important to note that if the guess file is not specified, the number\n"
  "of states must be specified.  Additionally, a guess file must be specified\n"
  "if the HMM type is 'mixture'.\n"
  "\n"
  "See the documentation in the 'formats' submodule (--help=formats) for more\n"
  "information on the file formats that this program uses.\n"
};

int main(int argc, char* argv[]) {
  fx_init(argc, argv, &hmm_train_main_doc);
  success_t s = SUCCESS_PASS;
  if (fx_param_exists(NULL, "type")) {
    const char* algorithm = fx_param_str(NULL, "algorithm", "baumwelch");
    if (strcmp(algorithm, "baumwelch") == 0)
      s = train_baumwelch();
    else if (strcmp(algorithm, "viterbi") == 0)
      s = train_viterbi();
    else {
      FATAL("Unrecognized training algorithm: must be 'baumwelch' or 'viterbi'.\n");
      s = SUCCESS_FAIL;
    }
  }
  else {
    FATAL("Unrecognized HMM type; must be 'discrete', 'gaussian', or 'mixture'.\n");
    s = SUCCESS_FAIL;
  }

  fx_done(NULL);
}

success_t train_baumwelch_discrete();
success_t train_baumwelch_gaussian();
success_t train_baumwelch_mixture();

success_t train_baumwelch() {
  const char* type = fx_param_str_req(NULL, "type");
  if (strcmp(type, "discrete")==0)
    return train_baumwelch_discrete();
  else if (strcmp(type, "gaussian")==0)
    return train_baumwelch_gaussian();
  else if (strcmp(type, "mixture")==0)
    return train_baumwelch_mixture();

  return SUCCESS_FAIL;
}

success_t train_viterbi_discrete();
success_t train_viterbi_gaussian();
success_t train_viterbi_mixture();

success_t train_viterbi() {
  const char* type = fx_param_str_req(NULL, "type");
  if (strcmp(type, "discrete")==0)
    return train_viterbi_discrete();
  else if (strcmp(type, "gaussian")==0)
    return train_viterbi_gaussian();
  else if (strcmp(type, "mixture")==0)
    return train_viterbi_mixture();

  return SUCCESS_FAIL;
}

success_t train_baumwelch_mixture() {
  MixtureofGaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.mix.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else {
    hmm.Init();
    FATAL("Automatic initialization not supported for mixture training.");
    return SUCCESS_FAIL;
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_baumwelch_gaussian() {
  GaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.gauss.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generating HMM parameters: %d states...", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_baumwelch_discrete() {
  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.dis.hmm");

  ArrayList<Vector> seqs;
  load_vector_list(seqin, &seqs);

  DiscreteHMM hmm;

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading HMM parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise randomly initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Randomly generating parameters: %d states...", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Baum-Welch algorithm...");
  hmm.TrainBaumWelch(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_mixture() {
  MixtureofGaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.mix.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading parameters from guess file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else {
    hmm.Init();
    FATAL("Automatic initialization not supported for mixture training.");
    return SUCCESS_FAIL;
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_gaussian() {
  GaussianHMM hmm;
  ArrayList<Matrix> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.gauss.hmm");

  load_matrix_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generating parameters with %d states\n", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}

success_t train_viterbi_discrete() {
  DiscreteHMM hmm;
  ArrayList<Vector> seqs;

  const char* seqin = fx_param_str_req(NULL, "input_file");
  const char* proout = fx_param_str(NULL, "output_model", "output.dis.hmm");

  load_vector_list(seqin, &seqs);

  if (fx_param_exists(NULL, "guess_model")) { // guessed parameters in a file
    ArrayList<Matrix> matlst;
    const char* guess = fx_param_str_req(NULL, "guess_model");
    NOTIFY("Loading guess parameters from file %s...", guess);
    hmm.InitFromFile(guess);
  }
  else { // otherwise randomly initialized using information from the data
    int numstate = fx_param_int_req(NULL, "num_states");
    NOTIFY("Generate parameters with %d states\n", numstate);
    hmm.InitFromData(seqs, numstate);
  }

  int maxiter = fx_param_int(NULL, "max_iter", 500);
  double tol = fx_param_double(NULL, "tolerance", 1e-3);

  NOTIFY("Training using Viterbi algorithm...");
  hmm.TrainViterbi(seqs, maxiter, tol);

  hmm.SaveProfile(proout);

  return SUCCESS_PASS;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "sal/config.h"

#include <map>
#include <utility>
#include <vector>

#include "sourcefileprovider.hxx"
#include "sourceprovider-scanner.hxx"

namespace unoidl { namespace detail {

namespace {

class Cursor: public MapCursor {
public:
    explicit Cursor(std::map< OUString, rtl::Reference<Entity> > const & map):
        map_(map), iterator_(map_.begin())
    {}

private:
    virtual ~Cursor() throw () {}

    virtual rtl::Reference< Entity > getNext(OUString * name) SAL_OVERRIDE;

    std::map< OUString, rtl::Reference<Entity> > const & map_; //TODO: extent
    std::map< OUString, rtl::Reference<Entity> >::const_iterator iterator_;
};

rtl::Reference< Entity > Cursor::getNext(OUString * name) {
    assert(name != 0);
    rtl::Reference< Entity > ent;
    if (iterator_ != map_.end()) {
        *name = iterator_->first;
        ent = iterator_->second;
        ++iterator_;
    }
    return ent;
}

class Module: public ModuleEntity {
public:
    Module() {}

    std::map< OUString, rtl::Reference<Entity> > map;

private:
    virtual ~Module() throw () {}

    virtual std::vector<rtl::OUString> getMemberNames() const SAL_OVERRIDE;

    virtual rtl::Reference<MapCursor> createCursor() const SAL_OVERRIDE
    { return new Cursor(map); }
};

std::vector<rtl::OUString> Module::getMemberNames() const {
    std::vector<rtl::OUString> names;
    for (std::map< OUString, rtl::Reference<Entity> >::const_iterator i(
             map.begin());
         i != map.end(); ++i)
    {
        names.push_back(i->first);
    }
    return names;
}

}

SourceFileProvider::SourceFileProvider(
    rtl::Reference<Manager> const & manager, OUString const & uri)
{
    SourceProviderScannerData data(manager);
    if (!parse(uri, &data)) {
        throw NoSuchFileException(uri);
    }
    for (std::map<OUString, SourceProviderEntity>::iterator i(
             data.entities.begin());
         i != data.entities.end(); ++i)
    {
        if (i->second.kind == SourceProviderEntity::KIND_LOCAL) {
            assert(i->second.entity.is());
            assert(i->second.entity->getSort() != Entity::SORT_MODULE);
            std::map< OUString, rtl::Reference<Entity> > * map = &rootMap_;
            for (sal_Int32 j = 0;;) {
                OUString id(i->first.getToken(0, '.', j));
                if (j == -1) {
                    map->insert(std::make_pair(id, i->second.entity));
                    break;
                }
                std::map< OUString, rtl::Reference<Entity> >::const_iterator k(
                    map->find(id));
                if (k == map->end()) {
                    k = map->insert(std::make_pair(id, new Module)).first;
                }
                Module * mod = dynamic_cast< Module * >(k->second.get());
                assert(mod != 0);
                map = &mod->map;
            }
        }
    }
}

rtl::Reference<MapCursor> SourceFileProvider::createRootCursor() const {
    return new Cursor(rootMap_);
}

rtl::Reference<Entity> SourceFileProvider::findEntity(OUString const & name)
    const
{
    std::map< OUString, rtl::Reference<Entity> > const * map = &rootMap_;
    for (sal_Int32 i = 0;;) {
        OUString id(name.getToken(0, '.', i));
        std::map< OUString, rtl::Reference<Entity> >::const_iterator j(
            map->find(id));
        if (j == map->end()) {
            return rtl::Reference<Entity>();
        }
        if (i == -1) {
            return j->second;
        }
        if (j->second->getSort() != Entity::SORT_MODULE) {
            return rtl::Reference<Entity>();
        }
        Module * mod = dynamic_cast< Module * >(j->second.get());
        assert(mod != 0);
        map = &mod->map;
    }
}

SourceFileProvider::~SourceFileProvider() throw () {}

} }

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#1242422 Unchecked dynamic_cast<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "sal/config.h"

#include <map>
#include <utility>
#include <vector>

#include "sourcefileprovider.hxx"
#include "sourceprovider-scanner.hxx"

namespace unoidl { namespace detail {

namespace {

class Cursor: public MapCursor {
public:
    explicit Cursor(std::map< OUString, rtl::Reference<Entity> > const & map):
        map_(map), iterator_(map_.begin())
    {}

private:
    virtual ~Cursor() throw () {}

    virtual rtl::Reference< Entity > getNext(OUString * name) SAL_OVERRIDE;

    std::map< OUString, rtl::Reference<Entity> > const & map_; //TODO: extent
    std::map< OUString, rtl::Reference<Entity> >::const_iterator iterator_;
};

rtl::Reference< Entity > Cursor::getNext(OUString * name) {
    assert(name != 0);
    rtl::Reference< Entity > ent;
    if (iterator_ != map_.end()) {
        *name = iterator_->first;
        ent = iterator_->second;
        ++iterator_;
    }
    return ent;
}

class Module: public ModuleEntity {
public:
    Module() {}

    std::map< OUString, rtl::Reference<Entity> > map;

private:
    virtual ~Module() throw () {}

    virtual std::vector<rtl::OUString> getMemberNames() const SAL_OVERRIDE;

    virtual rtl::Reference<MapCursor> createCursor() const SAL_OVERRIDE
    { return new Cursor(map); }
};

std::vector<rtl::OUString> Module::getMemberNames() const {
    std::vector<rtl::OUString> names;
    for (std::map< OUString, rtl::Reference<Entity> >::const_iterator i(
             map.begin());
         i != map.end(); ++i)
    {
        names.push_back(i->first);
    }
    return names;
}

}

SourceFileProvider::SourceFileProvider(
    rtl::Reference<Manager> const & manager, OUString const & uri)
{
    SourceProviderScannerData data(manager);
    if (!parse(uri, &data)) {
        throw NoSuchFileException(uri);
    }
    for (std::map<OUString, SourceProviderEntity>::iterator i(
             data.entities.begin());
         i != data.entities.end(); ++i)
    {
        if (i->second.kind == SourceProviderEntity::KIND_LOCAL) {
            assert(i->second.entity.is());
            assert(i->second.entity->getSort() != Entity::SORT_MODULE);
            std::map< OUString, rtl::Reference<Entity> > * map = &rootMap_;
            for (sal_Int32 j = 0;;) {
                OUString id(i->first.getToken(0, '.', j));
                if (j == -1) {
                    map->insert(std::make_pair(id, i->second.entity));
                    break;
                }
                std::map< OUString, rtl::Reference<Entity> >::const_iterator k(
                    map->find(id));
                if (k == map->end()) {
                    k = map->insert(std::make_pair(id, new Module)).first;
                }
                Module& mod = dynamic_cast<Module&>(*k->second.get());
                map = &mod.map;
            }
        }
    }
}

rtl::Reference<MapCursor> SourceFileProvider::createRootCursor() const {
    return new Cursor(rootMap_);
}

rtl::Reference<Entity> SourceFileProvider::findEntity(OUString const & name)
    const
{
    std::map< OUString, rtl::Reference<Entity> > const * map = &rootMap_;
    for (sal_Int32 i = 0;;) {
        OUString id(name.getToken(0, '.', i));
        std::map< OUString, rtl::Reference<Entity> >::const_iterator j(
            map->find(id));
        if (j == map->end()) {
            return rtl::Reference<Entity>();
        }
        if (i == -1) {
            return j->second;
        }
        if (j->second->getSort() != Entity::SORT_MODULE) {
            return rtl::Reference<Entity>();
        }
        Module * mod = dynamic_cast< Module * >(j->second.get());
        assert(mod != 0);
        map = &mod->map;
    }
}

SourceFileProvider::~SourceFileProvider() throw () {}

} }

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#ifndef _SV_SALMATHUTILS_HXX
    #include <salmathutils.hxx>
#endif

#include <stdlib.h>

// =======================================================================

// =======================================================================

#define Swap( x, y ) { x ^= y; y ^= x; x ^= y; }

// =======================================================================

// =======================================================================

// Storage free swapping using XOR

void CSwap ( char &rX, char &rY )
{
    Swap( rX, rY );
} // CSwap

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

// Storage free swapping using XOR

void UCSwap ( unsigned char &rX, unsigned char &rY )
{
    Swap( rX, rY );
} // UCSwap

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

// Storage free swapping using XOR

void SSwap ( short &rX, short &rY )
{
    Swap( rX, rY );
} // SSwap

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

// Storage free swapping using XOR

void USSwap ( unsigned short &rX, unsigned short &rY )
{
    Swap( rX, rY );
} // USSwap

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

// Storage free swapping using XOR

void LSwap ( long &rX, long &rY )
{
    Swap( rX, rY );
} // LSwap

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

// Storage free swapping using XOR

void ULSwap ( unsigned long &rX, unsigned long &rY )
{
    Swap( rX, rY );
} // ULSwap

// =======================================================================

// =======================================================================

// -----------------------------------------------------------------------
//
// This way of measuring distance is also called the "Manhattan distance."
// Manhattan distance takes advantage of the fact that the sum of the
// lengths of the three components of a 3D vector is a rough approxima-
// tion of the vector's length.
//
// -----------------------------------------------------------------------

unsigned long  Euclidian2Norm ( const LRectCoorVector  pVec )
{
    unsigned long  ndist = 0;

    if ( pVec )
    {
        long           nDX  = 0;
        long           nDY  = 0;
        long           nDZ  = 0;
        unsigned long  nMax = 0;
        unsigned long  nMed = 0;
        unsigned long  nMin = 0;

        // Find |x'-x|, |y'-y|, and |z'-z| from (x,y,z) and (x',y',z')

        nDX = pVec[1].x - pVec[0].x;
        nDY = pVec[1].y - pVec[0].y;
        nDZ = pVec[1].z - pVec[0].z;

        nMax = (unsigned long)abs( nDX );
        nMed = (unsigned long)abs( nDY );
        nMin = (unsigned long)abs( nDZ );

        // Sort them (3 compares, 0-3 swaps)

        if ( nMax < nMed )
        {
            Swap( nMax, nMed );
        } // if

        if ( nMax < nMin )
        {
            Swap( nMax, nMin );
        } // if

        // Approximate Euclidian distance:
        //
        //    d = max + (11/32)*med + (1/4)*min
        //
        // with +/- 8% error, where the exact formulae for d is
        //
        //  || (x',y',z') - (x,y,z) || = { |x'-x|^2 + |y'-y|^2 + |z'-z|^2 }^(1/2)

        ndist = nMax + ( nMin >> 2UL )
                     + ( ( ( nMed << 3UL ) + ( nMed << 1UL ) + nMed ) >> 5UL );
    } // if

    return ndist;
} // RGBDistance

// =======================================================================

// =======================================================================

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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include "salmathutils.hxx"

#include <stdlib.h>

// =======================================================================

// =======================================================================

#define Swap( x, y ) { x ^= y; y ^= x; x ^= y; }

// =======================================================================

// =======================================================================

// Storage free swapping using XOR

void CSwap ( char &rX, char &rY )
{
    Swap( rX, rY );
} // CSwap

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

// Storage free swapping using XOR

void UCSwap ( unsigned char &rX, unsigned char &rY )
{
    Swap( rX, rY );
} // UCSwap

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

// Storage free swapping using XOR

void SSwap ( short &rX, short &rY )
{
    Swap( rX, rY );
} // SSwap

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

// Storage free swapping using XOR

void USSwap ( unsigned short &rX, unsigned short &rY )
{
    Swap( rX, rY );
} // USSwap

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

// Storage free swapping using XOR

void LSwap ( long &rX, long &rY )
{
    Swap( rX, rY );
} // LSwap

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

// Storage free swapping using XOR

void ULSwap ( unsigned long &rX, unsigned long &rY )
{
    Swap( rX, rY );
} // ULSwap

// =======================================================================

// =======================================================================

// -----------------------------------------------------------------------
//
// This way of measuring distance is also called the "Manhattan distance."
// Manhattan distance takes advantage of the fact that the sum of the
// lengths of the three components of a 3D vector is a rough approxima-
// tion of the vector's length.
//
// -----------------------------------------------------------------------

unsigned long  Euclidian2Norm ( const LRectCoorVector  pVec )
{
    unsigned long  ndist = 0;

    if ( pVec )
    {
        long           nDX  = 0;
        long           nDY  = 0;
        long           nDZ  = 0;
        unsigned long  nMax = 0;
        unsigned long  nMed = 0;
        unsigned long  nMin = 0;

        // Find |x'-x|, |y'-y|, and |z'-z| from (x,y,z) and (x',y',z')

        nDX = pVec[1].x - pVec[0].x;
        nDY = pVec[1].y - pVec[0].y;
        nDZ = pVec[1].z - pVec[0].z;

        nMax = (unsigned long)abs( nDX );
        nMed = (unsigned long)abs( nDY );
        nMin = (unsigned long)abs( nDZ );

        // Sort them (3 compares, 0-3 swaps)

        if ( nMax < nMed )
        {
            Swap( nMax, nMed );
        } // if

        if ( nMax < nMin )
        {
            Swap( nMax, nMin );
        } // if

        // Approximate Euclidian distance:
        //
        //    d = max + (11/32)*med + (1/4)*min
        //
        // with +/- 8% error, where the exact formulae for d is
        //
        //  || (x',y',z') - (x,y,z) || = { |x'-x|^2 + |y'-y|^2 + |z'-z|^2 }^(1/2)

        ndist = nMax + ( nMin >> 2UL )
                     + ( ( ( nMed << 3UL ) + ( nMed << 1UL ) + nMed ) >> 5UL );
    } // if

    return ndist;
} // RGBDistance

// =======================================================================

// =======================================================================

<|endoftext|>


<commit_before>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Cycript is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#include <TargetConditionals.h>
#if defined(__arm__) || defined(__arm64__)
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_IPHONE_SIMULATOR 1
#endif
#define _PTHREAD_ATTR_T
#include <pthread_internals.h>
#if defined(__arm__) || defined(__arm64__)
#undef TARGET_IPHONE_SIMULATOR
#endif

#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>

#include "Standard.hpp"
#include "Baton.hpp"

static void $bzero(void *data, size_t size) {
    char *bytes(reinterpret_cast<char *>(data));
    for (size_t i(0); i != size; ++i)
        bytes[i] = 0;
}

static int $strcmp(const char *lhs, const char *rhs) {
    while (*lhs == *rhs) {
        if (*lhs == '\0')
            return 0;
        ++lhs, ++rhs;
    } return *lhs < *rhs ? -1 : 1;
}

static void $strlcpy(char *dst, const char *src, size_t size) {
    if (size == 0)
        return;
    size_t i(0);
    while (i != size - 1) {
        char value(src[i]);
        if (value == '\0')
            break;
        dst[i++] = value;
    } dst[i] = '\0';
}

#ifdef __LP64__
typedef struct mach_header_64 mach_header_xx;
typedef struct nlist_64 nlist_xx;
typedef struct segment_command_64 segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64;
static const uint32_t MH_MAGIC_XX = MH_MAGIC_64;
#else
typedef struct mach_header mach_header_xx;
typedef struct nlist nlist_xx;
typedef struct segment_command segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT;
static const uint32_t MH_MAGIC_XX = MH_MAGIC;
#endif

#define forlc(command, mach, lc, type) \
    if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
        if (const struct load_command *lcp = load_commands) \
            for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
                if ( \
                    lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
                    reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
                ) \
                    return NULL; \
                else if (lcp->cmd != lc) \
                    continue; \
                else if (lcp->cmdsize < sizeof(type)) \
                    return NULL; \
                else if (const type *command = reinterpret_cast<const type *>(lcp))

static const mach_header_xx *Library(struct dyld_all_image_infos *infos, const char *name) {
    for (uint32_t i(0); i != infos->infoArrayCount; ++i) {
        const dyld_image_info &info(infos->infoArray[i]);
        const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info.imageLoadAddress));
        if (mach->magic != MH_MAGIC_XX)
            continue;

        const char *path(info.imageFilePath);
        forlc (dylib, mach, LC_ID_DYLIB, dylib_command)
            path = reinterpret_cast<const char *>(dylib) + dylib->dylib.name.offset;
        if ($strcmp(path, name) != 0)
            continue;

        return mach;
    }

    return NULL;
}

static void *Symbol(const mach_header_xx *mach, const char *name) {
    const struct symtab_command *stp(NULL);
    forlc (command, mach, LC_SYMTAB, struct symtab_command)
        stp = command;
    if (stp == NULL)
        return NULL;

    size_t slide(_not(size_t));
    const nlist_xx *symbols(NULL);
    const char *strings(NULL);

    forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) {
        if (segment->fileoff == 0)
            slide = reinterpret_cast<size_t>(mach) - segment->vmaddr;
        if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize)
            symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide);
        if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize)
            strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide);
    }

    if (slide == _not(size_t) || symbols == NULL || strings == NULL)
        return NULL;

    for (size_t i(0); i != stp->nsyms; ++i) {
        const nlist_xx *symbol(&symbols[i]);
        if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0)
            continue;

        const char *nambuf(strings + symbol->n_un.n_strx);
        if ($strcmp(name, nambuf) != 0)
            continue;

        uintptr_t value(symbol->n_value);
        if (value == 0)
            continue;

#ifdef __arm__
        if ((symbol->n_desc & N_ARM_THUMB_DEF) != 0)
            value |= 0x00000001;
#endif

        value += slide;
        return reinterpret_cast<void *>(value);
    }

    return NULL;
}

template <typename Type_>
static _finline void cyset(Type_ &function, const char *name, const mach_header_xx *mach) {
    function = reinterpret_cast<Type_>(Symbol(mach, name));
}

static _finline const mach_header_xx *Library(Baton *baton, const char *name) {
    struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld));
    return Library(infos, name);
}

void *Routine(void *arg) {
    Baton *baton(reinterpret_cast<Baton *>(arg));

    const mach_header_xx *dyld(NULL);
    if (dyld == NULL)
        dyld = Library(baton, "/usr/lib/system/libdyld.dylib");
    if (dyld == NULL)
        dyld = Library(baton, "/usr/lib/libSystem.B.dylib");

    char *(*$dlerror)();
    cyset($dlerror, "_dlerror", dyld);

    void *(*$dlopen)(const char *, int);
    cyset($dlopen, "_dlopen", dyld);

    void *handle($dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
    if (handle == NULL) {
        $strlcpy(baton->error, $dlerror(), sizeof(baton->error));
        return NULL;
    }

    void *(*$dlsym)(void *, const char *);
    cyset($dlsym, "_dlsym", dyld);

    void (*CYHandleServer)(pid_t);
    CYHandleServer = reinterpret_cast<void (*)(pid_t)>($dlsym(handle, "CYHandleServer"));
    if (CYHandleServer == NULL) {
        $strlcpy(baton->error, $dlerror(), sizeof(baton->error));
        return NULL;
    }

    CYHandleServer(baton->pid);
    return NULL;
}

extern "C" void Start(Baton *baton) {
    struct _pthread self;
    $bzero(&self, sizeof(self));

    const mach_header_xx *pthread(NULL);
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/system/libsystem_pthread.dylib");
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/system/libsystem_c.dylib");
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/libSystem.B.dylib");

    void (*$__pthread_set_self)(pthread_t);
    cyset($__pthread_set_self, "___pthread_set_self", pthread);

    self.tsd[0] = &self;
    $__pthread_set_self(&self);

    int (*$pthread_attr_init)(pthread_attr_t *);
    cyset($pthread_attr_init, "_pthread_attr_init", pthread);

#if 0
    pthread_attr_t attr;
    $pthread_attr_init(&attr);

    int (*$pthread_attr_setdetachstate)(pthread_attr_t *, int);
    cyset($pthread_attr_setdetachstate, "_pthread_attr_setdetachstate", pthread);

    $pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#endif

    int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
    cyset($pthread_create, "_pthread_create", pthread);

    pthread_t thread;
    $pthread_create(&thread, NULL, &Routine, baton);

#if 0
    int (*$pthread_attr_destroy)(pthread_attr_t *);
    cyset($pthread_attr_destroy, "_pthread_attr_destroy", pthread);

    $pthread_attr_destroy(&attr);
#endif

#if defined(__arm__) || defined(__arm64__)
    uintptr_t tpid;
#if defined(__arm__)
    __asm__ ("mrc p15, 0, %0, c13, c0, 3\n" : "=r" (tpid));
#elif defined(__arm64__)
    __asm__ ("mrs %0, tpidrro_el0\n" : "=r" (tpid));
#else
#error XXX
#endif

    void **tsd;
    tsd = reinterpret_cast<void **>(tpid & ~3);
    if (tsd != NULL)
        tsd[0] = &self;
#else
    _pthread_setspecific_direct(0, &self);
#endif

    int (*$pthread_join)(pthread_t, void **);
    cyset($pthread_join, "_pthread_join", pthread);

    void *status;
    $pthread_join(thread, &status);

    const mach_header_xx *kernel(NULL);
    if (kernel == NULL)
        kernel = Library(baton, "/usr/lib/system/libsystem_kernel.dylib");
    if (kernel == NULL)
        kernel = Library(baton, "/usr/lib/libSystem.B.dylib");

    mach_port_t (*$mach_thread_self)();
    cyset($mach_thread_self, "_mach_thread_self", kernel);

    kern_return_t (*$thread_terminate)(thread_act_t);
    cyset($thread_terminate, "_thread_terminate", kernel);

    $thread_terminate($mach_thread_self());
}
<commit_msg>Apparently, __pthread_set_self takes tsd address.<commit_after>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Cycript is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#include <TargetConditionals.h>
#if defined(__arm__) || defined(__arm64__)
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_IPHONE_SIMULATOR 1
#endif
#define _PTHREAD_ATTR_T
#include <pthread_internals.h>
#if defined(__arm__) || defined(__arm64__)
#undef TARGET_IPHONE_SIMULATOR
#endif

#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>

#include "Standard.hpp"
#include "Baton.hpp"

static void $bzero(void *data, size_t size) {
    char *bytes(reinterpret_cast<char *>(data));
    for (size_t i(0); i != size; ++i)
        bytes[i] = 0;
}

static int $strcmp(const char *lhs, const char *rhs) {
    while (*lhs == *rhs) {
        if (*lhs == '\0')
            return 0;
        ++lhs, ++rhs;
    } return *lhs < *rhs ? -1 : 1;
}

static void $strlcpy(char *dst, const char *src, size_t size) {
    if (size == 0)
        return;
    size_t i(0);
    while (i != size - 1) {
        char value(src[i]);
        if (value == '\0')
            break;
        dst[i++] = value;
    } dst[i] = '\0';
}

#ifdef __LP64__
typedef struct mach_header_64 mach_header_xx;
typedef struct nlist_64 nlist_xx;
typedef struct segment_command_64 segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64;
static const uint32_t MH_MAGIC_XX = MH_MAGIC_64;
#else
typedef struct mach_header mach_header_xx;
typedef struct nlist nlist_xx;
typedef struct segment_command segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT;
static const uint32_t MH_MAGIC_XX = MH_MAGIC;
#endif

#define forlc(command, mach, lc, type) \
    if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
        if (const struct load_command *lcp = load_commands) \
            for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
                if ( \
                    lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
                    reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
                ) \
                    return NULL; \
                else if (lcp->cmd != lc) \
                    continue; \
                else if (lcp->cmdsize < sizeof(type)) \
                    return NULL; \
                else if (const type *command = reinterpret_cast<const type *>(lcp))

static const mach_header_xx *Library(struct dyld_all_image_infos *infos, const char *name) {
    for (uint32_t i(0); i != infos->infoArrayCount; ++i) {
        const dyld_image_info &info(infos->infoArray[i]);
        const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info.imageLoadAddress));
        if (mach->magic != MH_MAGIC_XX)
            continue;

        const char *path(info.imageFilePath);
        forlc (dylib, mach, LC_ID_DYLIB, dylib_command)
            path = reinterpret_cast<const char *>(dylib) + dylib->dylib.name.offset;
        if ($strcmp(path, name) != 0)
            continue;

        return mach;
    }

    return NULL;
}

static void *Symbol(const mach_header_xx *mach, const char *name) {
    const struct symtab_command *stp(NULL);
    forlc (command, mach, LC_SYMTAB, struct symtab_command)
        stp = command;
    if (stp == NULL)
        return NULL;

    size_t slide(_not(size_t));
    const nlist_xx *symbols(NULL);
    const char *strings(NULL);

    forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) {
        if (segment->fileoff == 0)
            slide = reinterpret_cast<size_t>(mach) - segment->vmaddr;
        if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize)
            symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide);
        if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize)
            strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide);
    }

    if (slide == _not(size_t) || symbols == NULL || strings == NULL)
        return NULL;

    for (size_t i(0); i != stp->nsyms; ++i) {
        const nlist_xx *symbol(&symbols[i]);
        if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0)
            continue;

        const char *nambuf(strings + symbol->n_un.n_strx);
        if ($strcmp(name, nambuf) != 0)
            continue;

        uintptr_t value(symbol->n_value);
        if (value == 0)
            continue;

#ifdef __arm__
        if ((symbol->n_desc & N_ARM_THUMB_DEF) != 0)
            value |= 0x00000001;
#endif

        value += slide;
        return reinterpret_cast<void *>(value);
    }

    return NULL;
}

template <typename Type_>
static _finline void cyset(Type_ &function, const char *name, const mach_header_xx *mach) {
    function = reinterpret_cast<Type_>(Symbol(mach, name));
}

static _finline const mach_header_xx *Library(Baton *baton, const char *name) {
    struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld));
    return Library(infos, name);
}

void *Routine(void *arg) {
    Baton *baton(reinterpret_cast<Baton *>(arg));

    const mach_header_xx *dyld(NULL);
    if (dyld == NULL)
        dyld = Library(baton, "/usr/lib/system/libdyld.dylib");
    if (dyld == NULL)
        dyld = Library(baton, "/usr/lib/libSystem.B.dylib");

    char *(*$dlerror)();
    cyset($dlerror, "_dlerror", dyld);

    void *(*$dlopen)(const char *, int);
    cyset($dlopen, "_dlopen", dyld);

    void *handle($dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
    if (handle == NULL) {
        $strlcpy(baton->error, $dlerror(), sizeof(baton->error));
        return NULL;
    }

    void *(*$dlsym)(void *, const char *);
    cyset($dlsym, "_dlsym", dyld);

    void (*CYHandleServer)(pid_t);
    CYHandleServer = reinterpret_cast<void (*)(pid_t)>($dlsym(handle, "CYHandleServer"));
    if (CYHandleServer == NULL) {
        $strlcpy(baton->error, $dlerror(), sizeof(baton->error));
        return NULL;
    }

    CYHandleServer(baton->pid);
    return NULL;
}

extern "C" void Start(Baton *baton) {
    struct _pthread self;
    $bzero(&self, sizeof(self));

    const mach_header_xx *pthread(NULL);
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/system/libsystem_pthread.dylib");
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/system/libsystem_c.dylib");
    if (pthread == NULL)
        pthread = Library(baton, "/usr/lib/libSystem.B.dylib");

    void (*$__pthread_set_self)(void **);
    cyset($__pthread_set_self, "___pthread_set_self", pthread);

    self.tsd[0] = &self;
    $__pthread_set_self(&self.tsd[0]);

    int (*$pthread_attr_init)(pthread_attr_t *);
    cyset($pthread_attr_init, "_pthread_attr_init", pthread);

#if 0
    pthread_attr_t attr;
    $pthread_attr_init(&attr);

    int (*$pthread_attr_setdetachstate)(pthread_attr_t *, int);
    cyset($pthread_attr_setdetachstate, "_pthread_attr_setdetachstate", pthread);

    $pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#endif

    int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
    cyset($pthread_create, "_pthread_create", pthread);

    pthread_t thread;
    $pthread_create(&thread, NULL, &Routine, baton);

#if 0
    int (*$pthread_attr_destroy)(pthread_attr_t *);
    cyset($pthread_attr_destroy, "_pthread_attr_destroy", pthread);

    $pthread_attr_destroy(&attr);
#endif

    int (*$pthread_join)(pthread_t, void **);
    cyset($pthread_join, "_pthread_join", pthread);

    void *status;
    $pthread_join(thread, &status);

    const mach_header_xx *kernel(NULL);
    if (kernel == NULL)
        kernel = Library(baton, "/usr/lib/system/libsystem_kernel.dylib");
    if (kernel == NULL)
        kernel = Library(baton, "/usr/lib/libSystem.B.dylib");

    mach_port_t (*$mach_thread_self)();
    cyset($mach_thread_self, "_mach_thread_self", kernel);

    kern_return_t (*$thread_terminate)(thread_act_t);
    cyset($thread_terminate, "_thread_terminate", kernel);

    $thread_terminate($mach_thread_self());
}
<|endoftext|>


<commit_before>//VBA_NestFunc.hpp
//Copyright (c) 2015 mmYYmmdd
#include "OAIdl.h"      //wtypes.h
#include <memory>
#include <array>

#if _MSC_VER < 1900
#define noexcept throw()
#endif

//VBA配列の次元取得
__int32 __stdcall   Dimension(const VARIANT* pv) noexcept;

//プレースホルダの生成
VARIANT __stdcall   placeholder(__int32) noexcept;

//プレースホルダの判定
__int32 __stdcall   is_placeholder(const VARIANT* pv) noexcept;

//bindされていないVBA関数を2引数で呼び出す
VARIANT __stdcall   unbind_invoke(VARIANT* bfun, VARIANT* param1, VARIANT* param2) noexcept;

//--------------------------------------------------------
// SafeArray要素のアクセス
class safearrayRef {
    SAFEARRAY*      psa;
    VARTYPE         pvt;
    std::size_t     dim;
    std::size_t     elemsize;
    char*           it;
    VARIANT         val_;
    std::array<std::size_t, 3>  size;
public:
    explicit safearrayRef(const VARIANT* pv) noexcept;
    ~safearrayRef();
    safearrayRef(safearrayRef const&) = delete;
    safearrayRef(safearrayRef&&) = delete;
    std::size_t getDim() const noexcept;
    std::size_t getSize(std::size_t i) const noexcept;
    std::size_t getOriginalLBound(std::size_t i) const noexcept;
    VARIANT& operator()(std::size_t i, std::size_t j = 0, std::size_t k = 0) noexcept;
};

//--------------------------------------------------------
//関数のインタフェース
class funcExpr_i {
public:
    virtual ~funcExpr_i() = default;
    virtual VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept = 0;
};

//--------------------------------------------------------
//使用する唯一のVBAコールバック関数型  vbCallbackFunc_t
//VBAにおけるシグネチャは
// Function fun(ByRef elem As Variant, ByRef dummy As Variant) As Variant
// もしくは
// Function fun(ByRef elem As Variant, Optional ByRef dummy As Variant) As Variant
using vbCallbackFunc_t = VARIANT(__stdcall *)(VARIANT*, VARIANT*);

namespace {
    struct VBCallbackStruct;
}

//VBA関数の表現
class functionExpr : public funcExpr_i {
    vbCallbackFunc_t    fun;
    VARIANT             val;
    std::unique_ptr<funcExpr_i> left;
    std::unique_ptr<funcExpr_i> right;
    functionExpr(functionExpr const&) = delete;
    functionExpr(functionExpr&&) = delete;
public:
    explicit functionExpr(const VARIANT*) noexcept;
    explicit functionExpr(const VBCallbackStruct&) noexcept;
    ~functionExpr();
    VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept;
    bool isValid() const noexcept;
};

//関数の引数としての関数（関数合成ではない）
class innerFunction : public funcExpr_i {
    VARIANT             myVal;
    VARIANT&            val;
    int                 phn1;
    int                 phn2;
    innerFunction(innerFunction const&) = delete;
    innerFunction(innerFunction&&) = delete;
    void eval_imple(VARIANT*, VARIANT*, VARIANT*, int, int&) noexcept;
public:
    innerFunction(VARIANT*, bool) noexcept;
    ~innerFunction();
    VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept;
};
<commit_msg>innerFunction バグ改修<commit_after>//VBA_NestFunc.hpp
//Copyright (c) 2015 mmYYmmdd
#include "OAIdl.h"      //wtypes.h
#include <memory>
#include <array>

#if _MSC_VER < 1900
#define noexcept throw()
#endif

//VBA配列の次元取得
__int32 __stdcall   Dimension(const VARIANT* pv) noexcept;

//プレースホルダの生成
VARIANT __stdcall   placeholder(__int32) noexcept;

//プレースホルダの判定
__int32 __stdcall   is_placeholder(const VARIANT* pv) noexcept;

//bindされていないVBA関数を2引数で呼び出す
VARIANT __stdcall   unbind_invoke(VARIANT* bfun, VARIANT* param1, VARIANT* param2) noexcept;

//--------------------------------------------------------
// SafeArray要素のアクセス
class safearrayRef {
    SAFEARRAY*      psa;
    VARTYPE         pvt;
    std::size_t     dim;
    std::size_t     elemsize;
    char*           it;
    VARIANT         val_;
    std::array<std::size_t, 3>  size;
public:
    explicit safearrayRef(const VARIANT* pv) noexcept;
    ~safearrayRef();
    safearrayRef(safearrayRef const&) = delete;
    safearrayRef(safearrayRef&&) = delete;
    std::size_t getDim() const noexcept;
    std::size_t getSize(std::size_t i) const noexcept;
    std::size_t getOriginalLBound(std::size_t i) const noexcept;
    VARIANT& operator()(std::size_t i, std::size_t j = 0, std::size_t k = 0) noexcept;
};

//--------------------------------------------------------
//関数のインタフェース
class funcExpr_i {
public:
    virtual ~funcExpr_i() = default;
    virtual VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept = 0;
};

//--------------------------------------------------------
//使用する唯一のVBAコールバック関数型  vbCallbackFunc_t
//VBAにおけるシグネチャは
// Function fun(ByRef elem As Variant, ByRef dummy As Variant) As Variant
// もしくは
// Function fun(ByRef elem As Variant, Optional ByRef dummy As Variant) As Variant
using vbCallbackFunc_t = VARIANT(__stdcall *)(VARIANT*, VARIANT*);

namespace {
    struct VBCallbackStruct;
}

//VBA関数の表現
class functionExpr : public funcExpr_i {
    vbCallbackFunc_t    fun;
    VARIANT             val;
    std::unique_ptr<funcExpr_i> left;
    std::unique_ptr<funcExpr_i> right;
    functionExpr(functionExpr const&) = delete;
    functionExpr(functionExpr&&) = delete;
public:
    explicit functionExpr(const VARIANT*) noexcept;
    explicit functionExpr(const VBCallbackStruct&) noexcept;
    ~functionExpr();
    VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept;
    bool isValid() const noexcept;
};

//関数の引数としての関数（関数合成ではない）
class innerFunction : public funcExpr_i {
    VARIANT             myVal;
    VARIANT&            val;
    int                 phn1;
    int                 phn2;
    std::unique_ptr<innerFunction>  arg1;
    std::unique_ptr<innerFunction>  arg2;
    innerFunction(innerFunction const&) = delete;
    innerFunction(innerFunction&&) = delete;
    void eval_imple(VARIANT*, VARIANT*, VARIANT*, int, int) noexcept;
public:
    innerFunction(VARIANT*, bool) noexcept;
    ~innerFunction();
    VARIANT* eval(VARIANT*, VARIANT*, int left_right = 0) noexcept;
};
<|endoftext|>