<commit_before>#include "asocket.h"

// STL
#include <cassert>
#include <cstring>
#include <cstdint>
#include <iostream>

// PDTK
#include "cxxutils/error_helpers.h"
#include "cxxutils/streamcolors.h"
#include "nonposix/getpeercred.h"

#ifndef CMSG_LEN
#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~ (sizeof(size_t) - 1))
#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr)))
#define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
#endif

static_assert(sizeof(uint8_t) == sizeof(char), "size mismatch!");

namespace posix
{
  inline bool getpeercred(fd_t sockfd, proccred_t& cred)
    { return ::getpeercred(sockfd, cred) == posix::success; }
}

AsyncSocket::AsyncSocket(EDomain domain, EType type, EProtocol protocol, int flags)
  : AsyncSocket(posix::socket(domain, type, protocol, flags))
{
}

AsyncSocket::AsyncSocket(posix::fd_t socket)
  : m_socket(socket)
{
}

AsyncSocket::~AsyncSocket(void)
{
  if(m_read.is_connected())
    m_read.disconnect();
  if(m_write.is_connected())
    m_write.disconnect();
  if(m_socket != posix::invalid_descriptor)
    posix::close(m_socket);
  m_socket = posix::invalid_descriptor;
  if(m_selfaddr != EDomain::unspec)
    ::unlink(m_selfaddr.sun_path);
  m_accept.detach();

}

bool AsyncSocket::bind(const char *socket_path, int socket_backlog)
{
  if(m_read.is_connected())
    return false;

  assert(std::strlen(socket_path) < sizeof(sockaddr_un::sun_path));
  m_selfaddr = socket_path;
  m_selfaddr = EDomain::unix;
  bool ok = posix::bind(m_socket, m_selfaddr, m_selfaddr.size());
  ok = ok && posix::listen(m_socket, socket_backlog);
  if(ok)
    m_accept = std::thread(&AsyncSocket::async_accept, this);
  return ok;
}

void AsyncSocket::async_accept(void)
{
  posix::sockaddr_t m_peeraddr;
  proccred_t m_peercred;

  socklen_t addrlen;
  m_read.connection = posix::accept(m_socket, m_peeraddr, &addrlen);
  m_write.connection = ::dup(m_read.connection);
  if(m_read.is_connected() &&
     posix::getpeercred(m_read.connection, m_peercred))
  {
    enqueue(connectedToPeer, m_peeraddr, m_peercred);
    m_read .thread = std::thread(&AsyncSocket::async_read , this);
    m_write.thread = std::thread(&AsyncSocket::async_write, this);
  }
}

bool AsyncSocket::connect(const char *socket_path)
{
  if(m_read.is_connected())
    return false;

  assert(std::strlen(socket_path) < sizeof(sockaddr_un::sun_path));
  proccred_t m_peercred;
  posix::sockaddr_t m_peeraddr;
  m_peeraddr = socket_path;
  m_peeraddr = EDomain::unix;
  m_selfaddr = EDomain::unspec;

  m_read.connection = m_socket;
  bool ok = m_read.connect(m_peeraddr);
  ok = ok && posix::getpeercred(m_read.connection, m_peercred);
  if(ok)
  {
    m_write.connection = ::dup(m_read.connection);
    enqueue(connectedToPeer, m_peeraddr, m_peercred);
    m_read .thread = std::thread(&AsyncSocket::async_read , this);
    m_write.thread = std::thread(&AsyncSocket::async_write, this);
  }
  else
    m_read.connection = posix::invalid_descriptor;
  return ok;
}

void AsyncSocket::async_read(void)
{
  std::mutex m;
  msghdr msg = {};
  iovec iov = {};

  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  for(;;)
  {
    m_read.buffer.allocate(); // allocate 64KB buffer
    std::unique_lock<std::mutex> lk(m);
    m_read.condition.wait(lk, [this] { return m_read.is_connected(); } );

    iov.iov_base = m_read.buffer.data();
    iov.iov_len = m_read.buffer.capacity();
    if(m_read.buffer.expand(posix::recvmsg(m_read.connection, &msg, 0)))
    {
      if(msg.msg_controllen == CMSG_SPACE(sizeof(int)))
      {
        cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
        if(cmsg->cmsg_level == SOL_SOCKET &&
           cmsg->cmsg_type == SCM_RIGHTS &&
           cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
         m_read.fd = *reinterpret_cast<int*>(CMSG_DATA(cmsg));
      }
      else
        m_read.fd = posix::invalid_descriptor;
      enqueue<vqueue&, posix::fd_t>(readFinished, m_read.buffer, m_read.fd);
    }
    else // error
      std::cout << std::flush << std::endl << std::red << "error: " << ::strerror(errno) << std::none << std::endl << std::flush;
  }
}

void AsyncSocket::async_write(void)
{
  std::mutex m;
  msghdr msg = {};
  iovec iov = {};
  char aux_buffer[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(ucred))] = { 0 };

  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_control = aux_buffer;

  for(;;)
  {
    std::unique_lock<std::mutex> lk(m);
    m_write.condition.wait(lk, [this] { return m_write.is_connected() && !m_write.buffer.empty(); } );

    iov.iov_base = m_write.buffer.begin();
    iov.iov_len = m_write.buffer.size();

    msg.msg_controllen = 0;

    if(m_write.fd != posix::invalid_descriptor)
    {
      msg.msg_controllen = CMSG_SPACE(sizeof(int));
      cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
      cmsg->cmsg_level = SOL_SOCKET;
      cmsg->cmsg_type = SCM_RIGHTS;
      cmsg->cmsg_len = CMSG_LEN(sizeof(int));
      *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = m_write.fd;
    }

    int count = posix::sendmsg(m_write.connection, &msg, 0);
    if(count == posix::error_response) // error
      std::cout << std::flush << std::endl << std::red << "error: " << ::strerror(errno) << std::none << std::endl << std::flush;
    else
      enqueue(writeFinished, count);
    m_write.buffer.resize(0);
  }
}

bool AsyncSocket::read(void)
{
  if(!m_read.is_connected())
    return false;
  m_read.condition.notify_one();
  return true;
}

bool AsyncSocket::write(vqueue& buffer, posix::fd_t fd)
{
  if(!m_read.is_connected())
    return false;

  m_write.fd = fd;
  m_write.buffer = buffer; // share buffer memory
  m_write.condition.notify_one();
  return true;
}
<commit_msg>added buffer for control message<commit_after>#include "asocket.h"

// STL
#include <cassert>
#include <cstring>
#include <cstdint>
#include <iostream>

// PDTK
#include "cxxutils/error_helpers.h"
#include "cxxutils/streamcolors.h"
#include "nonposix/getpeercred.h"

#ifndef CMSG_LEN
#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & (size_t) ~ (sizeof(size_t) - 1))
#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr)))
#define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
#endif

static_assert(sizeof(uint8_t) == sizeof(char), "size mismatch!");

namespace posix
{
  inline bool getpeercred(fd_t sockfd, proccred_t& cred)
    { return ::getpeercred(sockfd, cred) == posix::success; }
}

AsyncSocket::AsyncSocket(EDomain domain, EType type, EProtocol protocol, int flags)
  : AsyncSocket(posix::socket(domain, type, protocol, flags))
{
}

AsyncSocket::AsyncSocket(posix::fd_t socket)
  : m_socket(socket)
{
}

AsyncSocket::~AsyncSocket(void)
{
  if(m_read.is_connected())
    m_read.disconnect();
  if(m_write.is_connected())
    m_write.disconnect();
  if(m_socket != posix::invalid_descriptor)
    posix::close(m_socket);
  m_socket = posix::invalid_descriptor;
  if(m_selfaddr != EDomain::unspec)
    ::unlink(m_selfaddr.sun_path);
  m_accept.detach();

}

bool AsyncSocket::bind(const char *socket_path, int socket_backlog)
{
  if(m_read.is_connected())
    return false;

  assert(std::strlen(socket_path) < sizeof(sockaddr_un::sun_path));
  m_selfaddr = socket_path;
  m_selfaddr = EDomain::unix;
  bool ok = posix::bind(m_socket, m_selfaddr, m_selfaddr.size());
  ok = ok && posix::listen(m_socket, socket_backlog);
  if(ok)
    m_accept = std::thread(&AsyncSocket::async_accept, this);
  return ok;
}

void AsyncSocket::async_accept(void)
{
  posix::sockaddr_t m_peeraddr;
  proccred_t m_peercred;

  socklen_t addrlen;
  m_read.connection = posix::accept(m_socket, m_peeraddr, &addrlen);
  m_write.connection = ::dup(m_read.connection);
  if(m_read.is_connected() &&
     posix::getpeercred(m_read.connection, m_peercred))
  {
    enqueue(connectedToPeer, m_peeraddr, m_peercred);
    m_read .thread = std::thread(&AsyncSocket::async_read , this);
    m_write.thread = std::thread(&AsyncSocket::async_write, this);
  }
}

bool AsyncSocket::connect(const char *socket_path)
{
  if(m_read.is_connected())
    return false;

  assert(std::strlen(socket_path) < sizeof(sockaddr_un::sun_path));
  proccred_t m_peercred;
  posix::sockaddr_t m_peeraddr;
  m_peeraddr = socket_path;
  m_peeraddr = EDomain::unix;
  m_selfaddr = EDomain::unspec;

  m_read.connection = m_socket;
  bool ok = m_read.connect(m_peeraddr);
  ok = ok && posix::getpeercred(m_read.connection, m_peercred);
  if(ok)
  {
    m_write.connection = ::dup(m_read.connection);
    enqueue(connectedToPeer, m_peeraddr, m_peercred);
    m_read .thread = std::thread(&AsyncSocket::async_read , this);
    m_write.thread = std::thread(&AsyncSocket::async_write, this);
  }
  else
    m_read.connection = posix::invalid_descriptor;
  return ok;
}

void AsyncSocket::async_read(void)
{
  std::mutex m;
  msghdr msg = {};
  iovec iov = {};
  char aux_buffer[CMSG_SPACE(sizeof(int))] = { 0 };

  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_control = aux_buffer;

  for(;;)
  {
    m_read.buffer.allocate(); // allocate 64KB buffer
    std::unique_lock<std::mutex> lk(m);
    m_read.condition.wait(lk, [this] { return m_read.is_connected(); } );

    iov.iov_base = m_read.buffer.data();
    iov.iov_len = m_read.buffer.capacity();
    msg.msg_controllen = sizeof(aux_buffer);

    if(m_read.buffer.expand(posix::recvmsg(m_read.connection, &msg, 0)))
    {
      if(msg.msg_controllen == CMSG_SPACE(sizeof(int)))
      {
        cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
        if(cmsg->cmsg_level == SOL_SOCKET &&
           cmsg->cmsg_type == SCM_RIGHTS &&
           cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
         m_read.fd = *reinterpret_cast<int*>(CMSG_DATA(cmsg));
      }
      else if(msg.msg_flags & MSG_CTRUNC)
      {
        std::cout << std::flush << std::endl << std::red << "error: " << ::strerror(errno) << std::none << std::endl << std::flush;
      }
      else
        m_read.fd = posix::invalid_descriptor;
      enqueue<vqueue&, posix::fd_t>(readFinished, m_read.buffer, m_read.fd);
    }
    else // error
      std::cout << std::flush << std::endl << std::red << "error: " << ::strerror(errno) << std::none << std::endl << std::flush;
  }
}

void AsyncSocket::async_write(void)
{
  std::mutex m;
  msghdr msg = {};
  iovec iov = {};
  char aux_buffer[CMSG_SPACE(sizeof(int))] = { 0 };

  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_control = aux_buffer;

  for(;;)
  {
    std::unique_lock<std::mutex> lk(m);
    m_write.condition.wait(lk, [this] { return m_write.is_connected() && !m_write.buffer.empty(); } );

    iov.iov_base = m_write.buffer.begin();
    iov.iov_len = m_write.buffer.size();

    msg.msg_controllen = 0;

    if(m_write.fd != posix::invalid_descriptor)
    {
      msg.msg_controllen = CMSG_SPACE(sizeof(int));
      cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
      cmsg->cmsg_level = SOL_SOCKET;
      cmsg->cmsg_type = SCM_RIGHTS;
      cmsg->cmsg_len = CMSG_LEN(sizeof(int));
      *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = m_write.fd;
      m_write.fd = posix::invalid_descriptor;
    }

    int count = posix::sendmsg(m_write.connection, &msg, 0);
    if(count == posix::error_response) // error
      std::cout << std::flush << std::endl << std::red << "error: " << ::strerror(errno) << std::none << std::endl << std::flush;
    else
      enqueue(writeFinished, count);
    m_write.buffer.resize(0);
  }
}

bool AsyncSocket::read(void)
{
  if(!m_read.is_connected())
    return false;
  m_read.condition.notify_one();
  return true;
}

bool AsyncSocket::write(vqueue& buffer, posix::fd_t fd)
{
  if(!m_read.is_connected())
    return false;

  m_write.fd = fd;
  m_write.buffer = buffer; // share buffer memory
  m_write.condition.notify_one();
  return true;
}
<|endoftext|>


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

#include "xwalk/application/browser/application_event_router.h"

#include <algorithm>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents_observer.h"
#include "xwalk/application/browser/application_event_manager.h"
#include "xwalk/application/browser/application_service.h"
#include "xwalk/application/browser/application_system.h"

namespace xwalk {
namespace application {

ApplicationEventRouter::ApplicationEventRouter(
    ApplicationSystem* system, const std::string& app_id)
    : system_(system),
      app_id_(app_id),
      application_launched_(false) {
}

ApplicationEventRouter::~ApplicationEventRouter() {
  DetachAllObservers();
}

void ApplicationEventRouter::DidStopLoading(
    content::RenderViewHost* render_view_host) {
  application_launched_ = true;
  ProcessLazyEvents();
}

void ApplicationEventRouter::RenderProcessGone(
    base::TerminationStatus status) {
  application_launched_ = false;
  DetachAllObservers();
}

void ApplicationEventRouter::ObserveMainDocument(
    content::WebContents* contents) {
  content::WebContentsObserver::Observe(contents);
}

void ApplicationEventRouter::SetMainEvents(
    const std::set<std::string>& events) {
  main_events_ = events;
}

void ApplicationEventRouter::AttachObserver(const std::string& event_name,
                                            EventObserver* observer) {
  if (!ContainsKey(observers_, event_name)) {
    observers_.insert(std::make_pair(
          event_name, new ObserverList<EventObserver>()));
  }
  observers_[event_name]->AddObserver(observer);
}

void ApplicationEventRouter::DetachObserver(const std::string& event_name,
                                            EventObserver* observer) {
  if (!ContainsKey(observers_, event_name)) {
    DLOG(WARNING) << "Can't find attached observer for application(" << app_id_
                  << ") with event(" << event_name << ").";
    return;
  }

  observers_[event_name]->RemoveObserver(observer);
  if (!observers_[event_name]->might_have_observers()) {
    observers_.erase(event_name);
  }
}

void ApplicationEventRouter::DetachObserver(EventObserver* observer) {
  ObserverListMap::iterator it = observers_.begin();
  for (; it != observers_.end(); ++it)
    DetachObserver(it->first, observer);
}

void ApplicationEventRouter::DispatchEvent(scoped_refptr<Event> event) {
  ApplicationService* service = system_->application_service();
  const std::string& event_name = event->name();

  if (main_events_.find(event_name) != main_events_.end() ||
      event_name == "app.onLaunched") {
    if (!application_launched_) {
      if (lazy_events_.empty() && !service->Launch(app_id_))
        LOG(WARNING) << "Fail to launch application:" << app_id_;
      else
        lazy_events_.push_back(event);
      return;
    }
  }

  if (!application_launched_) {
    LOG(WARNING) << "Ignore event: " << event_name
                 << " send to terminated application:" << app_id_;
    return;
  }

  if (!ContainsKey(observers_, event_name) ||
      !observers_[event_name]->might_have_observers()) {
    LOG(INFO) << "No registered handler to handle event:" << event_name;
    return;
  }

  ProcessEvent(event);
}

void ApplicationEventRouter::DetachAllObservers() {
  ObserverListMap::iterator it = observers_.begin();
  for (; it != observers_.end(); ++it) {
    it->second->Clear();
  }
  observers_.clear();
}

void ApplicationEventRouter::ProcessLazyEvents() {
  if (lazy_events_.empty())
    return;

  EventVector::iterator it = lazy_events_.begin();
  for (; it != lazy_events_.end(); ++it)
    ProcessEvent(*it);
  lazy_events_.clear();
}

void ApplicationEventRouter::ProcessEvent(scoped_refptr<Event> event) {
  const std::string& event_name = event->name();
  DCHECK(ContainsKey(observers_, event_name));
  FOR_EACH_OBSERVER(
      EventObserver, *observers_[event_name], Observe(app_id_, event));
}

}  // namespace application
}  // namespace xwalk
<commit_msg>[Runtime] Fix application event router observer detach iteration bug<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/application/browser/application_event_router.h"

#include <algorithm>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents_observer.h"
#include "xwalk/application/browser/application_event_manager.h"
#include "xwalk/application/browser/application_service.h"
#include "xwalk/application/browser/application_system.h"

namespace xwalk {
namespace application {

ApplicationEventRouter::ApplicationEventRouter(
    ApplicationSystem* system, const std::string& app_id)
    : system_(system),
      app_id_(app_id),
      application_launched_(false) {
}

ApplicationEventRouter::~ApplicationEventRouter() {
  DetachAllObservers();
}

void ApplicationEventRouter::DidStopLoading(
    content::RenderViewHost* render_view_host) {
  application_launched_ = true;
  ProcessLazyEvents();
}

void ApplicationEventRouter::RenderProcessGone(
    base::TerminationStatus status) {
  application_launched_ = false;
  DetachAllObservers();
}

void ApplicationEventRouter::ObserveMainDocument(
    content::WebContents* contents) {
  content::WebContentsObserver::Observe(contents);
}

void ApplicationEventRouter::SetMainEvents(
    const std::set<std::string>& events) {
  main_events_ = events;
}

void ApplicationEventRouter::AttachObserver(const std::string& event_name,
                                            EventObserver* observer) {
  if (!ContainsKey(observers_, event_name)) {
    observers_.insert(std::make_pair(
          event_name, new ObserverList<EventObserver>()));
  }
  observers_[event_name]->AddObserver(observer);
}

void ApplicationEventRouter::DetachObserver(const std::string& event_name,
                                            EventObserver* observer) {
  if (!ContainsKey(observers_, event_name)) {
    DLOG(WARNING) << "Can't find attached observer for application(" << app_id_
                  << ") with event(" << event_name << ").";
    return;
  }

  observers_[event_name]->RemoveObserver(observer);
  if (!observers_[event_name]->might_have_observers()) {
    observers_.erase(event_name);
  }
}

void ApplicationEventRouter::DetachObserver(EventObserver* observer) {
  ObserverListMap::iterator it = observers_.begin();
  while (it != observers_.end())
    DetachObserver((it++)->first, observer);
}

void ApplicationEventRouter::DispatchEvent(scoped_refptr<Event> event) {
  ApplicationService* service = system_->application_service();
  const std::string& event_name = event->name();

  if (main_events_.find(event_name) != main_events_.end() ||
      event_name == "app.onLaunched") {
    if (!application_launched_) {
      if (lazy_events_.empty() && !service->Launch(app_id_))
        LOG(WARNING) << "Fail to launch application:" << app_id_;
      else
        lazy_events_.push_back(event);
      return;
    }
  }

  if (!application_launched_) {
    LOG(WARNING) << "Ignore event: " << event_name
                 << " send to terminated application:" << app_id_;
    return;
  }

  if (!ContainsKey(observers_, event_name) ||
      !observers_[event_name]->might_have_observers()) {
    LOG(INFO) << "No registered handler to handle event:" << event_name;
    return;
  }

  ProcessEvent(event);
}

void ApplicationEventRouter::DetachAllObservers() {
  ObserverListMap::iterator it = observers_.begin();
  for (; it != observers_.end(); ++it) {
    it->second->Clear();
  }
  observers_.clear();
}

void ApplicationEventRouter::ProcessLazyEvents() {
  if (lazy_events_.empty())
    return;

  EventVector::iterator it = lazy_events_.begin();
  for (; it != lazy_events_.end(); ++it)
    ProcessEvent(*it);
  lazy_events_.clear();
}

void ApplicationEventRouter::ProcessEvent(scoped_refptr<Event> event) {
  const std::string& event_name = event->name();
  DCHECK(ContainsKey(observers_, event_name));
  FOR_EACH_OBSERVER(
      EventObserver, *observers_[event_name], Observe(app_id_, event));
}

}  // namespace application
}  // namespace xwalk
<|endoftext|>


<commit_before><commit_msg>fixed slightly incorrect unchoke condition<commit_after><|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program. If not, see <http://www.gnu.org/licenses/>.              *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
/************************************************************************************
 * Contributors:                                                                    *
 *    - damien.marchal@univ-lille1.fr                                               *
 ***********************************************************************************/
#include <sofa/core/ObjectFactory.h>
using sofa::core::ObjectFactory ;

#include <SofaSimulationGraph/DAGSimulation.h>
using sofa::simulation::graph::DAGSimulation ;

#include "SimpleApi.h"
using sofa::core::objectmodel::BaseObjectDescription ;

namespace sofa
{
namespace simpleapi
{

Simulation::SPtr createSimulation(const std::string& type)
{
    if(type!="DAG")
    {
        msg_error("SimpleApi") << "Unable to create simulation of type '"<<type<<"'. Supported type is ['DAG']";
        return nullptr ;
    }

    return new simulation::graph::DAGSimulation() ;
}

Node::SPtr createRootNode(Simulation::SPtr s, const std::string& name,
                                              const std::map<std::string, std::string>& params)
{
    Node::SPtr root = s->createNewNode(name) ;

    BaseObjectDescription desc(type.c_str(),type.c_str());
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }
    root->parse(desc) ;

    return root ;
}

BaseObject::SPtr createObject(Node::SPtr parent, const std::string& type, const std::map<std::string, std::string>& params)
{
    /// temporarily, the name is set to the type name.
    /// if a "name" parameter is provided, it will overwrite it.
    BaseObjectDescription desc(type.c_str(),type.c_str());
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }

    /// Create the object.
    BaseObject::SPtr obj = ObjectFactory::getInstance()->createObject(parent.get(), &desc);
    if (obj==0)
    {
        std::stringstream msg;
        msg << "create: component '" << desc.getName() << "' of type '" << desc.getAttribute("type","") ;
        for (std::vector< std::string >::const_iterator it = desc.getErrors().begin(); it != desc.getErrors().end(); ++it)
            msg << " " << *it << msgendl ;
        msg_error(parent.get()) << msg.str() ;
        return NULL;
    }

    parent->addObject(obj) ;
    return obj ;
}

Node::SPtr createChild(Node::SPtr& node, const std::string& name, const std::map<std::string, std::string>& params)
{
    BaseObjectDescription desc("Node", "Node");
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }
    Node::SPtr tmp = node->createChild(name);
    tmp->parse(&desc);
    return tmp;
}

} /// simpleapi
} /// sofa
<commit_msg>[SceneCreator] Fix a typo causing compilation problem.<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program. If not, see <http://www.gnu.org/licenses/>.              *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
/************************************************************************************
 * Contributors:                                                                    *
 *    - damien.marchal@univ-lille1.fr                                               *
 ***********************************************************************************/
#include <sofa/core/ObjectFactory.h>
using sofa::core::ObjectFactory ;

#include <SofaSimulationGraph/DAGSimulation.h>
using sofa::simulation::graph::DAGSimulation ;

#include "SimpleApi.h"
using sofa::core::objectmodel::BaseObjectDescription ;

namespace sofa
{
namespace simpleapi
{

Simulation::SPtr createSimulation(const std::string& type)
{
    if(type!="DAG")
    {
        msg_error("SimpleApi") << "Unable to create simulation of type '"<<type<<"'. Supported type is ['DAG']";
        return nullptr ;
    }

    return new simulation::graph::DAGSimulation() ;
}

Node::SPtr createRootNode(Simulation::SPtr s, const std::string& name,
                                              const std::map<std::string, std::string>& params)
{
    Node::SPtr root = s->createNewNode(name) ;

    BaseObjectDescription desc("Node", "Node");
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }
    root->parse(&desc) ;

    return root ;
}

BaseObject::SPtr createObject(Node::SPtr parent, const std::string& type, const std::map<std::string, std::string>& params)
{
    /// temporarily, the name is set to the type name.
    /// if a "name" parameter is provided, it will overwrite it.
    BaseObjectDescription desc(type.c_str(),type.c_str());
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }

    /// Create the object.
    BaseObject::SPtr obj = ObjectFactory::getInstance()->createObject(parent.get(), &desc);
    if (obj==0)
    {
        std::stringstream msg;
        msg << "create: component '" << desc.getName() << "' of type '" << desc.getAttribute("type","") << "' " ;
        for (std::vector< std::string >::const_iterator it = desc.getErrors().begin(); it != desc.getErrors().end(); ++it)
            msg << " " << *it << msgendl ;
        msg_error(parent.get()) << msg.str() ;
        return NULL;
    }

    parent->addObject(obj) ;
    return obj ;
}

Node::SPtr createChild(Node::SPtr& node, const std::string& name, const std::map<std::string, std::string>& params)
{
    BaseObjectDescription desc("Node", "Node");
    for(auto& kv : params)
    {
        desc.setAttribute(kv.first.c_str(), kv.second.c_str());
    }
    Node::SPtr tmp = node->createChild(name);
    tmp->parse(&desc);
    return tmp;
}

} /// simpleapi
} /// sofa
<|endoftext|>


<commit_before>#ifndef VM_HH
#define VM_HH

#include <vector>
#include <stack>
#include <memory>

#include "lisp_ptr.hh"
#include "cons.hh"
#include "symbol.hh"
#include "env.hh"

class VM_t {
  typedef std::stack<Lisp_ptr, std::vector<Lisp_ptr>> stack_t;

public:
  static constexpr int return_value_max = 32;

  VM_t();
  ~VM_t();

  void enter_frame(Env*);
  void leave_frame();

  Lisp_ptr find(Symbol*);
  void set(Symbol*, Lisp_ptr);
  void local_set(Symbol*, Lisp_ptr);

  SymTable& symtable(){
    return *symtable_;
  }

public:
  stack_t code;
  stack_t stack;
  Lisp_ptr return_value[return_value_max];
  Env* frame;

private:
  std::stack<Env*> frame_history_;
  SymTable* symtable_;
};

extern VM_t VM;

#include "vm.i.hh"

#endif //VM_HH
<commit_msg>noe uses shread_ptr for symtable<commit_after>#ifndef VM_HH
#define VM_HH

#include <vector>
#include <stack>
#include <memory>

#include "lisp_ptr.hh"
#include "cons.hh"
#include "symbol.hh"
#include "env.hh"

class VM_t {
  typedef std::stack<Lisp_ptr, std::vector<Lisp_ptr>> stack_t;

public:
  static constexpr int return_value_max = 32;

  VM_t();
  ~VM_t();

  void enter_frame(Env*);
  void leave_frame();

  Lisp_ptr find(Symbol*);
  void set(Symbol*, Lisp_ptr);
  void local_set(Symbol*, Lisp_ptr);

  SymTable& symtable(){
    return *symtable_;
  }

public:
  stack_t code;
  stack_t stack;
  Lisp_ptr return_value[return_value_max];
  Env* frame;

private:
  std::stack<Env*> frame_history_;
  std::shared_ptr<SymTable> symtable_;
};

extern VM_t VM;

#include "vm.i.hh"

#endif //VM_HH
<|endoftext|>


<commit_before>// Copyright (c) 2015 The Bitcoin Core developers
// Copyright (c) 2017-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(reverselock_tests)

BOOST_AUTO_TEST_CASE(reverselock_basics)
{
    Mutex mutex;
    WAIT_LOCK(mutex, lock);

    BOOST_CHECK(lock.owns_lock());
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
    }
    BOOST_CHECK(lock.owns_lock());
}

BOOST_AUTO_TEST_CASE(reverselock_multiple)
{
    Mutex mutex2;
    Mutex mutex;
    WAIT_LOCK(mutex2, lock2);
    WAIT_LOCK(mutex, lock);

    // Make sure undoing two locks succeeds
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
        REVERSE_LOCK(lock2);
        BOOST_CHECK(!lock2.owns_lock());
    }
    BOOST_CHECK(lock.owns_lock());
    BOOST_CHECK(lock2.owns_lock());
}

BOOST_AUTO_TEST_CASE(reverselock_errors)
{
    Mutex mutex2;
    Mutex mutex;
    WAIT_LOCK(mutex2, lock2);
    WAIT_LOCK(mutex, lock);

#ifdef DEBUG_LOCKORDER
    // Make sure trying to reverse lock a previous lock fails
    try {
        REVERSE_LOCK(lock2);
        BOOST_CHECK(false); // REVERSE_LOCK(lock2) succeeded
    } catch(...) { }
    BOOST_CHECK(lock2.owns_lock());
#endif

    // Make sure trying to reverse lock an unlocked lock fails
    lock.unlock();

    BOOST_CHECK(!lock.owns_lock());

    bool failed = false;
    try {
        REVERSE_LOCK(lock);
    } catch(...) {
        failed = true;
    }

    BOOST_CHECK(failed);
    BOOST_CHECK(!lock.owns_lock());

    // Locking the original lock after it has been taken by a reverse lock
    // makes no sense. Ensure that the original lock no longer owns the lock
    // after giving it to a reverse one.

    lock.lock();
    BOOST_CHECK(lock.owns_lock());
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
    }

    BOOST_CHECK(failed);
    BOOST_CHECK(lock.owns_lock());
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Remove unused boost includes in reverselock_tests.cpp<commit_after>// Copyright (c) 2015 The Bitcoin Core developers
// Copyright (c) 2017-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(reverselock_tests)

BOOST_AUTO_TEST_CASE(reverselock_basics)
{
    Mutex mutex;
    WAIT_LOCK(mutex, lock);

    BOOST_CHECK(lock.owns_lock());
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
    }
    BOOST_CHECK(lock.owns_lock());
}

BOOST_AUTO_TEST_CASE(reverselock_multiple)
{
    Mutex mutex2;
    Mutex mutex;
    WAIT_LOCK(mutex2, lock2);
    WAIT_LOCK(mutex, lock);

    // Make sure undoing two locks succeeds
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
        REVERSE_LOCK(lock2);
        BOOST_CHECK(!lock2.owns_lock());
    }
    BOOST_CHECK(lock.owns_lock());
    BOOST_CHECK(lock2.owns_lock());
}

BOOST_AUTO_TEST_CASE(reverselock_errors)
{
    Mutex mutex2;
    Mutex mutex;
    WAIT_LOCK(mutex2, lock2);
    WAIT_LOCK(mutex, lock);

#ifdef DEBUG_LOCKORDER
    // Make sure trying to reverse lock a previous lock fails
    try {
        REVERSE_LOCK(lock2);
        BOOST_CHECK(false); // REVERSE_LOCK(lock2) succeeded
    } catch(...) { }
    BOOST_CHECK(lock2.owns_lock());
#endif

    // Make sure trying to reverse lock an unlocked lock fails
    lock.unlock();

    BOOST_CHECK(!lock.owns_lock());

    bool failed = false;
    try {
        REVERSE_LOCK(lock);
    } catch(...) {
        failed = true;
    }

    BOOST_CHECK(failed);
    BOOST_CHECK(!lock.owns_lock());

    // Locking the original lock after it has been taken by a reverse lock
    // makes no sense. Ensure that the original lock no longer owns the lock
    // after giving it to a reverse one.

    lock.lock();
    BOOST_CHECK(lock.owns_lock());
    {
        REVERSE_LOCK(lock);
        BOOST_CHECK(!lock.owns_lock());
    }

    BOOST_CHECK(failed);
    BOOST_CHECK(lock.owns_lock());
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before><commit_msg>Revert indent length stack size change<commit_after><|endoftext|>


<commit_before>//
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2013 Project Chrono
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file at the top level of the distribution
// and at http://projectchrono.org/license-chrono.txt.
//

#include "unit_IRRLICHT/ChIrrApp.h"

namespace irr {

ChIrrApp::ChIrrApp(chrono::ChSystem* psystem,
                   const wchar_t* title,
                   core::dimension2d<u32> dimens,
                   bool do_fullscreen,
                   bool do_shadows,
                   video::E_DRIVER_TYPE mydriver)
    : ChIrrAppInterface(psystem, title, dimens, do_fullscreen, do_shadows, mydriver) {
    mconverter = new scene::ChIrrAssetConverter(*this);
}

ChIrrApp::~ChIrrApp() {
    if (mconverter)
        delete mconverter;
}

void ChIrrApp::AssetBind(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    GetAssetConverter()->Bind(mitem);
}

void ChIrrApp::AssetBindAll() {
    GetAssetConverter()->BindAll();
}

void ChIrrApp::AssetUpdate(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    GetAssetConverter()->Update(mitem);
}

void ChIrrApp::AssetUpdateAll() {
    GetAssetConverter()->UpdateAll();
}

void ChIrrApp::AddShadow(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    chrono::ChSharedPtr<chrono::ChIrrNodeAsset> myirrasset;
    myirrasset = GetAssetConverter()->GetIrrNodeAsset(mitem);
    if (!myirrasset.IsNull()) {
        _recurse_add_shadow(myirrasset->GetIrrlichtNode());
    }
}

void ChIrrApp::AddShadowAll() {
    chrono::ChSystem::IteratorPhysicsItems miter = this->GetSystem()->IterBeginPhysicsItems();
    while (miter.HasItem()) {
        AddShadow(*miter);
        ++miter;
    }
}

void ChIrrApp::_recurse_add_shadow(scene::ISceneNode* mnode) {
    scene::ISceneNodeList::ConstIterator it = mnode->getChildren().begin();
    for (; it != mnode->getChildren().end(); ++it) {
        _recurse_add_shadow((*it));
    }
    // add shadow only to leaves
    if (mnode->getChildren().getSize() == 0)
        GetEffects()->addShadowToNode(mnode);
}

}  // END_OF_NAMESPACE____
<commit_msg>Thread safety for Bind() of assets to GUI.<commit_after>//
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2013 Project Chrono
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file at the top level of the distribution
// and at http://projectchrono.org/license-chrono.txt.
//

#include "unit_IRRLICHT/ChIrrApp.h"

namespace irr {

ChIrrApp::ChIrrApp(chrono::ChSystem* psystem,
                   const wchar_t* title,
                   core::dimension2d<u32> dimens,
                   bool do_fullscreen,
                   bool do_shadows,
                   video::E_DRIVER_TYPE mydriver)
    : ChIrrAppInterface(psystem, title, dimens, do_fullscreen, do_shadows, mydriver) {
    mconverter = new scene::ChIrrAssetConverter(*this);
}

ChIrrApp::~ChIrrApp() {
    if (mconverter)
        delete mconverter;
}

void ChIrrApp::AssetBind(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    #pragma omp critical
    GetAssetConverter()->Bind(mitem);
}

void ChIrrApp::AssetBindAll() {
    GetAssetConverter()->BindAll();
}

void ChIrrApp::AssetUpdate(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    GetAssetConverter()->Update(mitem);
}

void ChIrrApp::AssetUpdateAll() {
    GetAssetConverter()->UpdateAll();
}

void ChIrrApp::AddShadow(chrono::ChSharedPtr<chrono::ChPhysicsItem> mitem) {
    chrono::ChSharedPtr<chrono::ChIrrNodeAsset> myirrasset;
    myirrasset = GetAssetConverter()->GetIrrNodeAsset(mitem);
    if (!myirrasset.IsNull()) {
        _recurse_add_shadow(myirrasset->GetIrrlichtNode());
    }
}

void ChIrrApp::AddShadowAll() {
    chrono::ChSystem::IteratorPhysicsItems miter = this->GetSystem()->IterBeginPhysicsItems();
    while (miter.HasItem()) {
        AddShadow(*miter);
        ++miter;
    }
}

void ChIrrApp::_recurse_add_shadow(scene::ISceneNode* mnode) {
    scene::ISceneNodeList::ConstIterator it = mnode->getChildren().begin();
    for (; it != mnode->getChildren().end(); ++it) {
        _recurse_add_shadow((*it));
    }
    // add shadow only to leaves
    if (mnode->getChildren().getSize() == 0)
        GetEffects()->addShadowToNode(mnode);
}

}  // END_OF_NAMESPACE____
<|endoftext|>


<commit_before>#include <algorithm>
#include <vector>

#include "unittest/gtest.hpp"

#include "btree/node.hpp"
#include "btree/leaf_node.hpp"

namespace unittest {

// TODO: This is rather duplicative of fsck::check_value.
void expect_valid_value_shallowly(const btree_value *value) {
    EXPECT_TRUE(!(value->metadata_flags & ~(MEMCACHED_FLAGS | MEMCACHED_CAS | MEMCACHED_EXPTIME | LARGE_VALUE)));

    size_t size = value->value_size();

    if (value->is_large()) {
        EXPECT_GT(size, MAX_IN_NODE_VALUE_SIZE);

        // This isn't fsck, we can't follow large buf pointers.
    } else {
        EXPECT_LE(size, MAX_IN_NODE_VALUE_SIZE);
    }
}

// TODO: This is rather duplicative of fsck::check_subtree_leaf_node.
void verify(block_size_t block_size, const leaf_node_t *buf) {

    ASSERT_LE(offsetof(leaf_node_t, pair_offsets) + buf->npairs * 2, buf->frontmost_offset);
    ASSERT_LE(buf->frontmost_offset, block_size.value());

    std::vector<uint16_t> offsets(buf->pair_offsets, buf->pair_offsets + buf->npairs);
    std::sort(offsets.begin(), offsets.end());

    uint16_t expected = buf->frontmost_offset;
    for (std::vector<uint16_t>::const_iterator p = offsets.begin(), e = offsets.end(); p < e; ++p) {
        ASSERT_LE(expected, block_size.value());
        ASSERT_EQ(expected, *p);
        expected += leaf_node_handler::pair_size(leaf_node_handler::get_pair(buf, *p));
    }
    ASSERT_EQ(block_size.value(), expected);

    const btree_key *last_key = NULL;
    for (const uint16_t *p = buf->pair_offsets, *e = p + buf->npairs; p < e; ++p) {
        const btree_leaf_pair *pair = leaf_node_handler::get_pair(buf, *p);
        if (last_key != NULL) {
            const btree_key *next_key = &pair->key;
            EXPECT_LT(leaf_key_comp::compare(last_key, next_key), 0);
            last_key = next_key;
        }
        expect_valid_value_shallowly(pair->value());
    }
}

TEST(LeafNodeTest, Offsets) {
    // Check leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_node_t, magic));
    EXPECT_EQ(4, offsetof(leaf_node_t, times));
    EXPECT_EQ(12, offsetof(leaf_node_t, npairs));
    EXPECT_EQ(14, offsetof(leaf_node_t, frontmost_offset));
    EXPECT_EQ(16, offsetof(leaf_node_t, pair_offsets));
    EXPECT_EQ(16, sizeof(leaf_node_t));

    // Check leaf_timestamps_t, since that's specifically part of leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_timestamps_t, last_modified));
    EXPECT_EQ(4, offsetof(leaf_timestamps_t, earlier));

    // Changing NUM_LEAF_NODE_EARLIER_TIMES changes the disk format.
    EXPECT_EQ(2, NUM_LEAF_NODE_EARLIER_TIMES);

    EXPECT_EQ(8, sizeof(leaf_timestamps_t));

    // Check btree_leaf_pair.
    EXPECT_EQ(0, offsetof(btree_leaf_pair, key));

    btree_leaf_pair p;
    p.key.size = 173;
    EXPECT_EQ(174, reinterpret_cast<byte *>(p.value()) - reinterpret_cast<byte *>(&p));
}

block_size_t make_bs() {
    // TODO: Test weird block sizes.
    return block_size_t::unsafe_make(4096);
}

leaf_node_t *malloc_leaf_node(block_size_t bs) {
    return reinterpret_cast<leaf_node_t *>(malloc(bs.value()));
}

btree_key *malloc_key(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_KEY_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_KEY_SIZE);
    btree_key *k = reinterpret_cast<btree_key *>(malloc(sizeof(btree_key) + len));
    k->size = len;
    memcpy(k->contents, s, len);
    return k;
}

btree_value *malloc_value(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_IN_NODE_VALUE_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_IN_NODE_VALUE_SIZE);

    btree_value *v = reinterpret_cast<btree_value *>(malloc(sizeof(btree_value) + len));
    v->size = len;
    v->metadata_flags = 0;
    memcpy(v->value(), s, len);
    return v;
}

TEST(LeafNodeTest, Initialization) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node);
    free(node);
}

// Inserts one value and looks it up.
TEST(LeafNodeTest, InsertionLookup) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node);

    const char *key = "key";
    const char *value = "value";

    btree_key *k = malloc_key(key);
    btree_value *v = malloc_value(value);

    ASSERT_TRUE(leaf_node_handler::insert(bs, node, k, v, repli_timestamp::invalid));
    verify(bs, node);

    union {
        byte readval_padding[MAX_TOTAL_NODE_CONTENTS_SIZE + sizeof(btree_value)];
        btree_value readval;
    };

    (void)readval_padding;

    ASSERT_TRUE(leaf_node_handler::lookup(node, k, &readval));

    ASSERT_EQ(0, memcmp(v, &readval, v->full_size()));

    verify(bs, node);

    free(k);
    free(v);
    free(node);
}

}  // namespace unittest

<commit_msg>Changed InsertionLookup to InsertLookupRemove<commit_after>#include <algorithm>
#include <vector>

#include "unittest/gtest.hpp"

#include "btree/node.hpp"
#include "btree/leaf_node.hpp"

namespace unittest {

// TODO: This is rather duplicative of fsck::check_value.
void expect_valid_value_shallowly(const btree_value *value) {
    EXPECT_TRUE(!(value->metadata_flags & ~(MEMCACHED_FLAGS | MEMCACHED_CAS | MEMCACHED_EXPTIME | LARGE_VALUE)));

    size_t size = value->value_size();

    if (value->is_large()) {
        EXPECT_GT(size, MAX_IN_NODE_VALUE_SIZE);

        // This isn't fsck, we can't follow large buf pointers.
    } else {
        EXPECT_LE(size, MAX_IN_NODE_VALUE_SIZE);
    }
}

// TODO: This is rather duplicative of fsck::check_subtree_leaf_node.
void verify(block_size_t block_size, const leaf_node_t *buf) {

    ASSERT_LE(offsetof(leaf_node_t, pair_offsets) + buf->npairs * 2, buf->frontmost_offset);
    ASSERT_LE(buf->frontmost_offset, block_size.value());

    std::vector<uint16_t> offsets(buf->pair_offsets, buf->pair_offsets + buf->npairs);
    std::sort(offsets.begin(), offsets.end());

    uint16_t expected = buf->frontmost_offset;
    for (std::vector<uint16_t>::const_iterator p = offsets.begin(), e = offsets.end(); p < e; ++p) {
        ASSERT_LE(expected, block_size.value());
        ASSERT_EQ(expected, *p);
        expected += leaf_node_handler::pair_size(leaf_node_handler::get_pair(buf, *p));
    }
    ASSERT_EQ(block_size.value(), expected);

    const btree_key *last_key = NULL;
    for (const uint16_t *p = buf->pair_offsets, *e = p + buf->npairs; p < e; ++p) {
        const btree_leaf_pair *pair = leaf_node_handler::get_pair(buf, *p);
        if (last_key != NULL) {
            const btree_key *next_key = &pair->key;
            EXPECT_LT(leaf_key_comp::compare(last_key, next_key), 0);
            last_key = next_key;
        }
        expect_valid_value_shallowly(pair->value());
    }
}

TEST(LeafNodeTest, Offsets) {
    // Check leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_node_t, magic));
    EXPECT_EQ(4, offsetof(leaf_node_t, times));
    EXPECT_EQ(12, offsetof(leaf_node_t, npairs));
    EXPECT_EQ(14, offsetof(leaf_node_t, frontmost_offset));
    EXPECT_EQ(16, offsetof(leaf_node_t, pair_offsets));
    EXPECT_EQ(16, sizeof(leaf_node_t));

    // Check leaf_timestamps_t, since that's specifically part of leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_timestamps_t, last_modified));
    EXPECT_EQ(4, offsetof(leaf_timestamps_t, earlier));

    // Changing NUM_LEAF_NODE_EARLIER_TIMES changes the disk format.
    EXPECT_EQ(2, NUM_LEAF_NODE_EARLIER_TIMES);

    EXPECT_EQ(8, sizeof(leaf_timestamps_t));

    // Check btree_leaf_pair.
    EXPECT_EQ(0, offsetof(btree_leaf_pair, key));

    btree_leaf_pair p;
    p.key.size = 173;
    EXPECT_EQ(174, reinterpret_cast<byte *>(p.value()) - reinterpret_cast<byte *>(&p));
}

block_size_t make_bs() {
    // TODO: Test weird block sizes.
    return block_size_t::unsafe_make(4096);
}

leaf_node_t *malloc_leaf_node(block_size_t bs) {
    return reinterpret_cast<leaf_node_t *>(malloc(bs.value()));
}

btree_key *malloc_key(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_KEY_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_KEY_SIZE);
    btree_key *k = reinterpret_cast<btree_key *>(malloc(sizeof(btree_key) + len));
    k->size = len;
    memcpy(k->contents, s, len);
    return k;
}

btree_value *malloc_value(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_IN_NODE_VALUE_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_IN_NODE_VALUE_SIZE);

    btree_value *v = reinterpret_cast<btree_value *>(malloc(sizeof(btree_value) + len));
    v->size = len;
    v->metadata_flags = 0;
    memcpy(v->value(), s, len);
    return v;
}

TEST(LeafNodeTest, Initialization) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node);
    free(node);
}

// Inserts one value and looks it up and removes it.
TEST(LeafNodeTest, InsertLookupRemove) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node);

    const char *key = "key";
    const char *value = "value";

    btree_key *k = malloc_key(key);
    btree_value *v = malloc_value(value);

    ASSERT_TRUE(leaf_node_handler::insert(bs, node, k, v, repli_timestamp::invalid));
    verify(bs, node);
    ASSERT_EQ(1, node->npairs);

    union {
        byte readval_padding[MAX_TOTAL_NODE_CONTENTS_SIZE + sizeof(btree_value)];
        btree_value readval;
    };

    (void)readval_padding;

    ASSERT_TRUE(leaf_node_handler::lookup(node, k, &readval));

    ASSERT_EQ(0, memcmp(v, &readval, v->full_size()));

    leaf_node_handler::remove(bs, node, k);
    verify(bs, node);
    ASSERT_EQ(0, node->npairs);

    free(k);
    free(v);
    free(node);
}

}  // namespace unittest

<|endoftext|>


<commit_before>#include "gt_matrix.h"
#include "popstatem.h"
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>

GT_Matrix::GT_Matrix(std::string filename, int ploidy):
ploidy(ploidy), gts(Genotype::enumerate_gts(ploidy)), data(std::vector<double>(gts.size()),Genotype::alleles.size()){
	std::ifstream f;
	f.exceptions ( ifstream::failbit | ifstream::badbit );
	f.open(filename);
	std::string line;
	while(std::getline(f,line)){

	}
}

GT_Matrix::GT_Matrix(Pileupdata plpdata, int ploidy, theta_t theta, std::map<char,double> pi):
ploidy(ploidy), gts(Genotype::enumerate_gts(ploidy)), data(std::vector<double>(gts.size()),Genotype::alleles.size()){
	for (pileupdata_t::iterator tid = plpdata.begin(); tid != plpdata.end(); ++tid){
		for(std::vector<pileuptuple_t>::iterator pos = tid->begin(); pos != tid->end(); ++pos){
			const std::vector<char> &x = std::get<0>(*pos);
			const char &ref = std::get<3>(*pos);
			for (std::vector<Genotype>::iterator g = gts.begin(); g != gts.end(); ++g){
				double pg_x = Popstatem::pg_x_given_theta(*g,x,theta,pi);
				double pdata = Popstatem::pdata_given_theta(x,theta,gts);
				this(ref,*g) += pg_x / pdata;
			}
		}
	}
}

std::vector<double>& GT_Matrix::operator[](size_t i){
	return data[i];
}

std::vector<double>& GT_Matrix::operator[](char allele){
	return data[std::distance(data.begin(),std::find(data.begin(), data.end(), allele))]
}

double& GT_Matrix::operator()(char allele, Genotype gt){
	row = this[allele];
	ptrdiff_t idx = std::distance(row.begin(),std::find(row.begin(), row.end(), gt));
	return row[idx];
}

double& GT_Matrix::operator()(size_t i, size_t j){
	row = this[i];
	return row[j];
}

<commit_msg>add a close<commit_after>#include "gt_matrix.h"
#include "popstatem.h"
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>

GT_Matrix::GT_Matrix(std::string filename, int ploidy):
ploidy(ploidy), gts(Genotype::enumerate_gts(ploidy)), data(std::vector<double>(gts.size()),Genotype::alleles.size()){
	std::ifstream f;
	f.exceptions ( ifstream::failbit | ifstream::badbit );
	f.open(filename);
	std::string line;
	while(std::getline(f,line)){

	}
	f.close();
}

GT_Matrix::GT_Matrix(Pileupdata plpdata, int ploidy, theta_t theta, std::map<char,double> pi):
ploidy(ploidy), gts(Genotype::enumerate_gts(ploidy)), data(std::vector<double>(gts.size()),Genotype::alleles.size()){
	for (pileupdata_t::iterator tid = plpdata.begin(); tid != plpdata.end(); ++tid){
		for(std::vector<pileuptuple_t>::iterator pos = tid->begin(); pos != tid->end(); ++pos){
			const std::vector<char> &x = std::get<0>(*pos);
			const char &ref = std::get<3>(*pos);
			for (std::vector<Genotype>::iterator g = gts.begin(); g != gts.end(); ++g){
				double pg_x = Popstatem::pg_x_given_theta(*g,x,theta,pi);
				double pdata = Popstatem::pdata_given_theta(x,theta,gts);
				this(ref,*g) += pg_x / pdata;
			}
		}
	}
}

std::vector<double>& GT_Matrix::operator[](size_t i){
	return data[i];
}

std::vector<double>& GT_Matrix::operator[](char allele){
	return data[std::distance(data.begin(),std::find(data.begin(), data.end(), allele))]
}

double& GT_Matrix::operator()(char allele, Genotype gt){
	row = this[allele];
	ptrdiff_t idx = std::distance(row.begin(),std::find(row.begin(), row.end(), gt));
	return row[idx];
}

double& GT_Matrix::operator()(size_t i, size_t j){
	row = this[i];
	return row[j];
}

<|endoftext|>


<commit_before>#include <algorithm>
#include <vector>

#include "unittest/gtest.hpp"

#include "btree/node.hpp"
#include "btree/leaf_node.hpp"

namespace unittest {

// TODO: This is rather duplicative of fsck::check_value.
void expect_valid_value_shallowly(const btree_value *value) {
    EXPECT_TRUE(!(value->metadata_flags & ~(MEMCACHED_FLAGS | MEMCACHED_CAS | MEMCACHED_EXPTIME | LARGE_VALUE)));

    size_t size = value->value_size();

    if (value->is_large()) {
        EXPECT_GT(size, MAX_IN_NODE_VALUE_SIZE);

        // This isn't fsck, we can't follow large buf pointers.
    } else {
        EXPECT_LE(size, MAX_IN_NODE_VALUE_SIZE);
    }
}

// TODO: This is rather duplicative of fsck::check_subtree_leaf_node.
void verify(block_size_t block_size, const leaf_node_t *buf, int expected_free_space) {

    int end_of_pair_offsets = offsetof(leaf_node_t, pair_offsets) + buf->npairs * 2;
    ASSERT_LE(end_of_pair_offsets, buf->frontmost_offset);
    ASSERT_LE(buf->frontmost_offset, block_size.value());
    ASSERT_EQ(expected_free_space, buf->frontmost_offset - end_of_pair_offsets);

    std::vector<uint16_t> offsets(buf->pair_offsets, buf->pair_offsets + buf->npairs);
    std::sort(offsets.begin(), offsets.end());

    uint16_t expected = buf->frontmost_offset;
    for (std::vector<uint16_t>::const_iterator p = offsets.begin(), e = offsets.end(); p < e; ++p) {
        ASSERT_LE(expected, block_size.value());
        ASSERT_EQ(expected, *p);
        expected += leaf_node_handler::pair_size(leaf_node_handler::get_pair(buf, *p));
    }
    ASSERT_EQ(block_size.value(), expected);

    const btree_key *last_key = NULL;
    for (const uint16_t *p = buf->pair_offsets, *e = p + buf->npairs; p < e; ++p) {
        const btree_leaf_pair *pair = leaf_node_handler::get_pair(buf, *p);
        if (last_key != NULL) {
            const btree_key *next_key = &pair->key;
            EXPECT_LT(leaf_key_comp::compare(last_key, next_key), 0);
            last_key = next_key;
        }
        expect_valid_value_shallowly(pair->value());
    }
}

TEST(LeafNodeTest, Offsets) {
    // Check leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_node_t, magic));
    EXPECT_EQ(4, offsetof(leaf_node_t, times));
    EXPECT_EQ(12, offsetof(leaf_node_t, npairs));
    EXPECT_EQ(14, offsetof(leaf_node_t, frontmost_offset));
    EXPECT_EQ(16, offsetof(leaf_node_t, pair_offsets));
    EXPECT_EQ(16, sizeof(leaf_node_t));

    // Check leaf_timestamps_t, since that's specifically part of leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_timestamps_t, last_modified));
    EXPECT_EQ(4, offsetof(leaf_timestamps_t, earlier));

    // Changing NUM_LEAF_NODE_EARLIER_TIMES changes the disk format.
    EXPECT_EQ(2, NUM_LEAF_NODE_EARLIER_TIMES);

    EXPECT_EQ(8, sizeof(leaf_timestamps_t));

    // Check btree_leaf_pair.
    EXPECT_EQ(0, offsetof(btree_leaf_pair, key));

    btree_leaf_pair p;
    p.key.size = 173;
    EXPECT_EQ(174, reinterpret_cast<byte *>(p.value()) - reinterpret_cast<byte *>(&p));
}

class Value {
public:
    Value(const std::string& data = "", mcflags_t mcflags = 0, cas_t cas = 0, bool has_cas = false, exptime_t exptime = 0)
        : mcflags_(mcflags), cas_(cas), exptime_(exptime),
          has_cas_(has_cas),
          data_(data) {
        EXPECT_LE(data_.size(), MAX_IN_NODE_VALUE_SIZE);
    }

    void WriteBtreeValue(btree_value *out) const {
        out->size = 0;
        ASSERT_LE(data_.size(), MAX_IN_NODE_VALUE_SIZE);
        out->value_size(data_.size());
        out->set_mcflags(mcflags_);
        out->set_exptime(exptime_);
        if (has_cas_) {
            out->set_cas(cas_);
        }
    }

    static Value Make(const btree_value *v) {
        EXPECT_FALSE(v->is_large());
        return Value(std::string(v->value(), v->value() + v->value_size()),
                     v->mcflags(), v->has_cas() ? v->cas() : 0, v->has_cas(), v->exptime());
    }

    bool operator==(const Value& rhs) {
        return mcflags_ == rhs.mcflags_
            && exptime_ == rhs.exptime_
            && data_ == rhs.data_
            && has_cas_ == rhs.has_cas_
            && (has_cas_ ? cas_ == rhs.cas_ : true);
    }

    int full_size() const {
        return sizeof(btree_value) + (mcflags_ ? sizeof(mcflags_t) : 0) + (has_cas_ ? sizeof(cas_t) : 0)
            + (exptime_ ? sizeof(exptime_t) : 0) + data_.size();
    }

private:
    mcflags_t mcflags_;
    cas_t cas_;
    exptime_t exptime_;
    bool has_cas_;
    std::string data_;
};

class StackKey {
public:
    explicit StackKey(const std::string& key) {
        EXPECT_LE(key.size(), MAX_KEY_SIZE);
        keyval.size = key.size();
        memcpy(keyval.contents, key.c_str(), key.size());
    }

    const btree_key *look() const {
        return &keyval;
    }

private:
    union {
        byte keyval_padding[sizeof(btree_key) + MAX_KEY_SIZE];
        btree_key keyval;
    };
};

class StackValue {
public:
    StackValue() {
        memset(val_padding, 0, sizeof(val_padding));
    }
    explicit StackValue(const Value& value) {
        value.WriteBtreeValue(&val);
    }
    const btree_value *look() const {
        return &val;
    }
    btree_value *look_write() {
        return &val;
    }
private:
    union {
        byte val_padding[sizeof(btree_value) + MAX_TOTAL_NODE_CONTENTS_SIZE];
        btree_value val;
    };
};

template <int block_size>
class LeafNodeGrinder {
    block_size_t bs;
    typedef std::map<std::string, Value> expected_t;
    expected_t expected;
    int expected_free_space;
    leaf_node_t *node;

    void insert(const std::string& k, const Value& v) {
        if (expected_free_space < sizeof(*node->pair_offsets) + v.full_size()) {
            StackKey skey(k);
            StackValue sval(v);
            ASSERT_FALSE(leaf_node_handler::insert(bs, node, skey.look(), sval.look(), repli_timestamp::invalid));
        } else {
            std::pair<expected_t::iterator, bool> res = expected.insert(std::make_pair(k, v));
            if (res.second) {
                // The key didn't previously exist.
                expected_free_space -= v.full_size() + sizeof(*node->pair_offsets);
            } else {
                // The key previously existed.
                expected_free_space += res.first->second.full_size();
                expected_free_space -= v.full_size();
                res.first->second = v;
            }
        }

        verify(bs, node, expected_free_space);
    }

    // Expects the key to be in the node.
    void remove(const std::string& k) {
        expected_t::iterator p = expected.find(k);

        // There's a bug in the test if we're trying to remove a key that's not there.
        ASSERT_TRUE(p != expected.end());

        // The key should be in there.
        StackKey skey(k);
        StackValue sval();

        ASSERT_TRUE(leaf_node_handler::lookup(node, skey.look(), sval.look_write()));

        leaf_node_handler::remove(bs, node, skey.look());
        expected_free_space -= (sval.look()->full_size() + sizeof(sval.look()->pair_offsets[0]));

        verify(bs, node, expected_free_space);
    }

};

block_size_t make_bs() {
    // TODO: Test weird block sizes.
    return block_size_t::unsafe_make(4096);
}

leaf_node_t *malloc_leaf_node(block_size_t bs) {
    return reinterpret_cast<leaf_node_t *>(malloc(bs.value()));
}

btree_key *malloc_key(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_KEY_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_KEY_SIZE);
    btree_key *k = reinterpret_cast<btree_key *>(malloc(sizeof(btree_key) + len));
    k->size = len;
    memcpy(k->contents, s, len);
    return k;
}

btree_value *malloc_value(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_IN_NODE_VALUE_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_IN_NODE_VALUE_SIZE);

    btree_value *v = reinterpret_cast<btree_value *>(malloc(sizeof(btree_value) + len));
    v->size = len;
    v->metadata_flags = 0;
    memcpy(v->value(), s, len);
    return v;
}

TEST(LeafNodeTest, Initialization) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));
    free(node);
}

// Runs an InsertLookupRemove test with key and value.
void InsertLookupRemoveHelper(const char *key, const char *value) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));

    btree_key *k = malloc_key(key);
    btree_value *v = malloc_value(value);

    ASSERT_TRUE(leaf_node_handler::insert(bs, node, k, v, repli_timestamp::invalid));
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets) - k->full_size() - v->full_size() - 2);
    ASSERT_EQ(1, node->npairs);

    union {
        byte readval_padding[MAX_TOTAL_NODE_CONTENTS_SIZE + sizeof(btree_value)];
        btree_value readval;
    };

    (void)readval_padding;

    ASSERT_TRUE(leaf_node_handler::lookup(node, k, &readval));

    ASSERT_EQ(0, memcmp(v, &readval, v->full_size()));

    leaf_node_handler::remove(bs, node, k);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));
    ASSERT_EQ(0, node->npairs);

    free(k);
    free(v);
    free(node);
}

TEST(LeafNodeTest, ElementaryInsertLookupRemove) {
    InsertLookupRemoveHelper("the_key", "the_value");
}
TEST(LeafNodeTest, EmptyValueInsertLookupRemove) {
    InsertLookupRemoveHelper("the_key", "");
}
TEST(LeafNodeTest, EmptyKeyInsertLookupRemove) {
    InsertLookupRemoveHelper("", "the_value");
}
TEST(LeafNodeTest, EmptyKeyValueInsertLookupRemove) {
    InsertLookupRemoveHelper("", "");
}

}  // namespace unittest

<commit_msg>leaf_node_test in some horrible broken confusing state.<commit_after>#include <algorithm>
#include <vector>

#include "unittest/gtest.hpp"

#include "btree/node.hpp"
#include "btree/leaf_node.hpp"

namespace unittest {

// TODO: This is rather duplicative of fsck::check_value.
void expect_valid_value_shallowly(const btree_value *value) {
    EXPECT_EQ(0, value->metadata_flags & ~(MEMCACHED_FLAGS | MEMCACHED_CAS | MEMCACHED_EXPTIME | LARGE_VALUE));

    size_t size = value->value_size();

    if (value->is_large()) {
        EXPECT_GT(size, MAX_IN_NODE_VALUE_SIZE);

        // This isn't fsck, we can't follow large buf pointers.
    } else {
        EXPECT_LE(size, MAX_IN_NODE_VALUE_SIZE);
    }
}

// TODO: This is rather duplicative of fsck::check_subtree_leaf_node.
void verify(block_size_t block_size, const leaf_node_t *buf, int expected_free_space) {

    int end_of_pair_offsets = offsetof(leaf_node_t, pair_offsets) + buf->npairs * 2;
    ASSERT_LE(end_of_pair_offsets, buf->frontmost_offset);
    ASSERT_LE(buf->frontmost_offset, block_size.value());
    ASSERT_EQ(expected_free_space, buf->frontmost_offset - end_of_pair_offsets);

    std::vector<uint16_t> offsets(buf->pair_offsets, buf->pair_offsets + buf->npairs);
    std::sort(offsets.begin(), offsets.end());

    uint16_t expected = buf->frontmost_offset;
    for (std::vector<uint16_t>::const_iterator p = offsets.begin(), e = offsets.end(); p < e; ++p) {
        ASSERT_LE(expected, block_size.value());
        ASSERT_EQ(expected, *p);
        expected += leaf_node_handler::pair_size(leaf_node_handler::get_pair(buf, *p));
    }
    ASSERT_EQ(block_size.value(), expected);

    const btree_key *last_key = NULL;
    for (const uint16_t *p = buf->pair_offsets, *e = p + buf->npairs; p < e; ++p) {
        const btree_leaf_pair *pair = leaf_node_handler::get_pair(buf, *p);
        if (last_key != NULL) {
            const btree_key *next_key = &pair->key;
            EXPECT_LT(leaf_key_comp::compare(last_key, next_key), 0);
            last_key = next_key;
        }
        expect_valid_value_shallowly(pair->value());
    }
}

TEST(LeafNodeTest, Offsets) {
    // Check leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_node_t, magic));
    EXPECT_EQ(4, offsetof(leaf_node_t, times));
    EXPECT_EQ(12, offsetof(leaf_node_t, npairs));
    EXPECT_EQ(14, offsetof(leaf_node_t, frontmost_offset));
    EXPECT_EQ(16, offsetof(leaf_node_t, pair_offsets));
    EXPECT_EQ(16, sizeof(leaf_node_t));

    // Check leaf_timestamps_t, since that's specifically part of leaf_node_t.
    EXPECT_EQ(0, offsetof(leaf_timestamps_t, last_modified));
    EXPECT_EQ(4, offsetof(leaf_timestamps_t, earlier));

    // Changing NUM_LEAF_NODE_EARLIER_TIMES changes the disk format.
    EXPECT_EQ(2, NUM_LEAF_NODE_EARLIER_TIMES);

    EXPECT_EQ(8, sizeof(leaf_timestamps_t));

    // Check btree_leaf_pair.
    EXPECT_EQ(0, offsetof(btree_leaf_pair, key));

    btree_leaf_pair p;
    p.key.size = 173;
    EXPECT_EQ(174, reinterpret_cast<byte *>(p.value()) - reinterpret_cast<byte *>(&p));
}

class Value {
public:
    Value(const std::string& data = "", mcflags_t mcflags = 0, cas_t cas = 0, bool has_cas = false, exptime_t exptime = 0)
        : mcflags_(mcflags), cas_(cas), exptime_(exptime),
          has_cas_(has_cas),
          data_(data) {
        EXPECT_LE(data_.size(), MAX_IN_NODE_VALUE_SIZE);
    }

    void WriteBtreeValue(btree_value *out) const {
        out->size = 0;
        ASSERT_LE(data_.size(), MAX_IN_NODE_VALUE_SIZE);
        out->value_size(data_.size());
        out->set_mcflags(mcflags_);
        out->set_exptime(exptime_);
        if (has_cas_) {
            out->set_cas(cas_);
        }
        memcpy(v->value(), data_.c_str(), data_.size());
    }

    static Value Make(const btree_value *v) {
        EXPECT_FALSE(v->is_large());
        return Value(std::string(v->value(), v->value() + v->value_size()),
                     v->mcflags(), v->has_cas() ? v->cas() : 0, v->has_cas(), v->exptime());
    }

    bool operator==(const Value& rhs) const {
        return mcflags_ == rhs.mcflags_
            && exptime_ == rhs.exptime_
            && data_ == rhs.data_
            && has_cas_ == rhs.has_cas_
            && (has_cas_ ? cas_ == rhs.cas_ : true);
    }

    int full_size() const {
        return sizeof(btree_value) + (mcflags_ ? sizeof(mcflags_t) : 0) + (has_cas_ ? sizeof(cas_t) : 0)
            + (exptime_ ? sizeof(exptime_t) : 0) + data_.size();
    }

    friend std::ostream& operator<<(std::ostream&, const Value&);

private:
    mcflags_t mcflags_;
    cas_t cas_;
    exptime_t exptime_;
    bool has_cas_;
    std::string data_;
};

std::ostream& operator<<(std::ostream& out, const Value& v) {
    out << "Value[mcflags=" << v.mcflags_;
    if (v.has_cas_) {
        out << " cas=" << v.cas_;
    }

    // TODO: string escape v.data_.
    out << " exptime=" << v.exptime_
        << " data='" << v.data_ << "']";
    return out;
}

class StackKey {
public:
    explicit StackKey(const std::string& key) {
        EXPECT_LE(key.size(), MAX_KEY_SIZE);
        keyval.size = key.size();
        memcpy(keyval.contents, key.c_str(), key.size());
    }

    const btree_key *look() const {
        return &keyval;
    }

private:
    union {
        byte keyval_padding[sizeof(btree_key) + MAX_KEY_SIZE];
        btree_key keyval;
    };
};

class StackValue {
public:
    StackValue() {
        memset(val_padding, 0, sizeof(val_padding));
    }
    explicit StackValue(const Value& value) {
        value.WriteBtreeValue(&val);
    }
    const btree_value *look() const {
        return &val;
    }
    btree_value *look_write() {
        return &val;
    }
private:
    union {
        byte val_padding[sizeof(btree_value) + MAX_TOTAL_NODE_CONTENTS_SIZE];
        btree_value val;
    };
};

template <int block_size>
class LeafNodeGrinder {
    block_size_t bs;
    typedef std::map<std::string, Value> expected_t;
    expected_t expected;
    int expected_frontmost_offset;
    int expected_npairs;
    leaf_node_t *node;

public:
    LeafNodeGrinder() : bs(block_size_t::unsafe_make(block_size)), expected(), expected_frontmost_offset(bs.value()), expected_npairs(0), node(reinterpret_cast<leaf_node_t *>(malloc(bs.value()))) {
    }

    ~LeafNodeGrinder() {
        free(node);
    }

    int expected_space() const {
        return expected_frontmost_offset - (offsetof(leaf_node_t, pair_offsets) + sizeof(*node->pair_offsets) * expected_npairs);
    }

    void init() {
        SCOPED_TRACE("init");
        leaf_node_handler::init(bs, node, repli_timestamp::invalid);
        validate();
    }

    void insert(const std::string& k, const Value& v) {
        SCOPED_TRACE("insert");
        StackKey skey(k);
        StackValue sval(v);

        if (expected_space() < int((1 + k.size()) + v.full_size() + sizeof(*node->pair_offsets))) {
            ASSERT_FALSE(leaf_node_handler::insert(bs, node, skey.look(), sval.look(), repli_timestamp::invalid));
        } else {
            ASSERT_TRUE(leaf_node_handler::insert(bs, node, skey.look(), sval.look(), repli_timestamp::invalid));

            std::pair<expected_t::iterator, bool> res = expected.insert(std::make_pair(k, v));
            if (res.second) {
                // The key didn't previously exist.
                printf("new key '%s', subtracting %ld\n", k.c_str(), (1 + k.size()) + v.full_size() + sizeof(*node->pair_offsets));
                expected_frontmost_offset -= (1 + k.size()) + v.full_size();
                expected_npairs++;
            } else {
                // The key previously existed.
                printf("same key '%s', adding %d subtracting %d\n", k.c_str(),
                       res.first->second.full_size(), v.full_size());
                expected_frontmost_offset += res.first->second.full_size();
                expected_frontmost_offset -= v.full_size();
                res.first->second = v;
            }
        }

        validate();
    }

    void lookup(const std::string& k, const Value& expected) const {
        StackKey skey(k);
        StackValue sval;
        ASSERT_TRUE(leaf_node_handler::lookup(node, skey.look(), sval.look_write()));
        ASSERT_EQ(expected, Value::Make(sval.look()));
    }

    // Expects the key to be in the node.
    void remove(const std::string& k) {
        SCOPED_TRACE("remove");
        expected_t::iterator p = expected.find(k);

        // There's a bug in the test if we're trying to remove a key that's not there.
        ASSERT_TRUE(p != expected.end());

        // The key should be in there.
        StackKey skey(k);
        StackValue sval;

        ASSERT_TRUE(leaf_node_handler::lookup(node, skey.look(), sval.look_write()));

        leaf_node_handler::remove(bs, node, skey.look());
        expected.erase(p);
        printf("removal of '%s', adding %ld\n", k.c_str(), (1 + k.size()) + sval.look()->full_size() + sizeof(*node->pair_offsets));
        expected_frontmost_offset += (1 + k.size()) + sval.look()->full_size() + sizeof(*node->pair_offsets);

        validate();
    }

    void validate() const {
        ASSERT_EQ(expected_npairs, node->npairs);
        ASSERT_EQ(expected_frontmost_offset, node->frontmost_offset);

        verify(bs, node, expected_space());

        for (expected_t::const_iterator p = expected.begin(), e = expected.end(); p != e; ++p) {
            lookup(p->first, p->second);
        }

        // We're confident there are no bad keys because
        // expected_free_space matched up.
    }

};

block_size_t make_bs() {
    // TODO: Test weird block sizes.
    return block_size_t::unsafe_make(4096);
}

leaf_node_t *malloc_leaf_node(block_size_t bs) {
    return reinterpret_cast<leaf_node_t *>(malloc(bs.value()));
}

btree_key *malloc_key(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_KEY_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_KEY_SIZE);
    btree_key *k = reinterpret_cast<btree_key *>(malloc(sizeof(btree_key) + len));
    k->size = len;
    memcpy(k->contents, s, len);
    return k;
}

btree_value *malloc_value(const char *s) {
    size_t origlen = strlen(s);
    EXPECT_LE(origlen, MAX_IN_NODE_VALUE_SIZE);

    size_t len = std::min<size_t>(origlen, MAX_IN_NODE_VALUE_SIZE);

    btree_value *v = reinterpret_cast<btree_value *>(malloc(sizeof(btree_value) + len));
    v->size = len;
    v->metadata_flags = 0;
    memcpy(v->value(), s, len);
    return v;
}

TEST(LeafNodeTest, Initialization) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));
    free(node);
}

void AlternateInsertLookupRemoveHelper(const std::string& key, const char *value) {
    LeafNodeGrinder<4096> gr;

    Value v(value);

    gr.init();
    gr.insert(key, v);
    gr.lookup(key, v);
    gr.remove(key);
}

// Runs an InsertLookupRemove test with key and value.
void InsertLookupRemoveHelper(const char *key, const char *value) {
    block_size_t bs = make_bs();
    leaf_node_t *node = malloc_leaf_node(bs);

    leaf_node_handler::init(bs, node, repli_timestamp::invalid);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));

    btree_key *k = malloc_key(key);
    btree_value *v = malloc_value(value);

    ASSERT_TRUE(leaf_node_handler::insert(bs, node, k, v, repli_timestamp::invalid));
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets) - k->full_size() - v->full_size() - 2);
    ASSERT_EQ(1, node->npairs);

    union {
        byte readval_padding[MAX_TOTAL_NODE_CONTENTS_SIZE + sizeof(btree_value)];
        btree_value readval;
    };

    (void)readval_padding;

    ASSERT_TRUE(leaf_node_handler::lookup(node, k, &readval));

    ASSERT_EQ(0, memcmp(v, &readval, v->full_size()));

    leaf_node_handler::remove(bs, node, k);
    verify(bs, node, bs.value() - offsetof(leaf_node_t, pair_offsets));
    ASSERT_EQ(0, node->npairs);

    free(k);
    free(v);
    free(node);
}

TEST(LeafNodeTest, ElementaryInsertLookupRemove) {
    AlternateInsertLookupRemoveHelper("the_key", "the_value");
}
TEST(LeafNodeTest, EmptyValueInsertLookupRemove) {
    AlternateInsertLookupRemoveHelper("the_key", "");
}
TEST(LeafNodeTest, EmptyKeyInsertLookupRemove) {
    AlternateInsertLookupRemoveHelper("", "the_value");
}
TEST(LeafNodeTest, EmptyKeyValueInsertLookupRemove) {
    AlternateInsertLookupRemoveHelper("", "");
}

}  // namespace unittest

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017~2017 by CSSlayer
 * wengxt@gmail.com
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * 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; see the file COPYING. If not,
 * see <http://www.gnu.org/licenses/>.
 */

#include "unix/fcitx5/mozc_engine.h"

#include <fcitx-config/iniparser.h>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/standardpath.h>
#include <fcitx/inputcontext.h>
#include <fcitx/inputcontextmanager.h>
#include <fcitx/inputmethodmanager.h>
#include <fcitx/userinterfacemanager.h>

#include <vector>

#include "base/init_mozc.h"
#include "base/process.h"
#include "unix/fcitx5/mozc_connection.h"
#include "unix/fcitx5/mozc_response_parser.h"

namespace fcitx {

const struct CompositionMode {
  const char *name;
  const char *icon;
  const char *label;
  const char *description;
  mozc::commands::CompositionMode mode;
} kPropCompositionModes[] = {
    {
        "mozc-mode-direct",
        "fcitx-mozc-direct",
        "A",
        N_("Direct"),
        mozc::commands::DIRECT,
    },
    {
        "mozc-mode-hiragana",
        "fcitx-mozc-hiragana",
        "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
        N_("Hiragana"),
        mozc::commands::HIRAGANA,
    },
    {
        "mozc-mode-katakana_full",
        "fcitx-mozc-katakana-full",
        "\xe3\x82\xa2",  // Katakana letter A.
        N_("Full Katakana"),
        mozc::commands::FULL_KATAKANA,
    },
    {

        "mozc-mode-alpha_half",
        "fcitx-mozc-alpha-half",
        "A",
        N_("Half ASCII"),
        mozc::commands::HALF_ASCII,
    },
    {

        "mozc-mode-alpha_full",
        "fcitx-mozc-alpha-full",
        "\xef\xbc\xa1",  // Full width ASCII letter A.
        N_("Full ASCII"),
        mozc::commands::FULL_ASCII,
    },
    {
        "mozc-mode-katakana_half",
        "fcitx-mozc-katakana-half",
        "\xef\xbd\xb1",  // Half width Katakana letter A.
        N_("Half Katakana"),
        mozc::commands::HALF_KATAKANA,
    },
};
const size_t kNumCompositionModes = arraysize(kPropCompositionModes);

std::string MozcModeAction::shortText(InputContext *) const {
  return _("Composition Mode");
}

std::string MozcModeAction::longText(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return _(kPropCompositionModes[mozc_state->GetCompositionMode()].description);
}

std::string MozcModeAction::icon(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return kPropCompositionModes[mozc_state->GetCompositionMode()].icon;
}

MozcModeSubAction::MozcModeSubAction(MozcEngine *engine,
                                     mozc::commands::CompositionMode mode)
    : engine_(engine), mode_(mode) {
  setShortText(kPropCompositionModes[mode].description);
  setLongText(_(kPropCompositionModes[mode].description));
  setIcon(kPropCompositionModes[mode].icon);
  setCheckable(true);
}

bool MozcModeSubAction::isChecked(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return mozc_state->GetCompositionMode() == mode_;
}

void MozcModeSubAction::activate(InputContext *ic) {
  auto mozc_state = engine_->mozcState(ic);
  mozc_state->SendCompositionMode(mode_);
}

// This array must correspond with the CompositionMode enum in the
// mozc/session/command.proto file.
static_assert(mozc::commands::NUM_OF_COMPOSITIONS == kNumCompositionModes,
              "number of modes must match");

Instance *Init(Instance *instance) {
  int argc = 1;
  char argv0[] = "fcitx_mozc";
  char *_argv[] = {argv0};
  char **argv = _argv;
  mozc::InitMozc(argv[0], &argc, &argv);
  return instance;
}

MozcEngine::MozcEngine(Instance *instance)
    : instance_(Init(instance)),
      connection_(std::make_unique<MozcConnection>()),
      factory_([this](InputContext &ic) {
        return new MozcState(&ic, connection_->CreateClient(), this);
      }),
      modeAction_(this) {
  for (auto command :
       {mozc::commands::DIRECT, mozc::commands::HIRAGANA,
        mozc::commands::FULL_KATAKANA, mozc::commands::FULL_ASCII,
        mozc::commands::HALF_ASCII, mozc::commands::HALF_KATAKANA}) {
    modeActions_.push_back(std::make_unique<MozcModeSubAction>(this, command));
  }
  instance_->inputContextManager().registerProperty("mozcState", &factory_);
  instance_->userInterfaceManager().registerAction("mozc-mode", &modeAction_);
  instance_->userInterfaceManager().registerAction("mozc-tool", &toolAction_);
  toolAction_.setShortText(_("Tool"));
  toolAction_.setLongText(_("Tool"));
  toolAction_.setIcon("fcitx-mozc-tool");

  int i = 0;
  for (auto &modeAction : modeActions_) {
    instance_->userInterfaceManager().registerAction(
        kPropCompositionModes[i].name, modeAction.get());
    modeMenu_.addAction(modeAction.get());
    i++;
  }

  instance_->userInterfaceManager().registerAction("mozc-tool-config",
                                                   &configToolAction_);
  configToolAction_.setShortText(_("Configuration Tool"));
  configToolAction_.setIcon("fcitx-mozc-tool");
  configToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=config_dialog");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-dict",
                                                   &dictionaryToolAction_);
  dictionaryToolAction_.setShortText(_("Dictionary Tool"));
  dictionaryToolAction_.setIcon("fcitx-mozc-dictionary");
  dictionaryToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=dictionary_tool");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-add",
                                                   &addWordAction_);
  addWordAction_.setShortText(_("Add Word"));
  addWordAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=word_register_dialog");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-about",
                                                   &aboutAction_);
  aboutAction_.setShortText(_("About Mozc"));
  aboutAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=about_dialog");
  });

  toolMenu_.addAction(&configToolAction_);
  toolMenu_.addAction(&dictionaryToolAction_);
  toolMenu_.addAction(&addWordAction_);
  toolMenu_.addAction(&aboutAction_);

  modeAction_.setMenu(&modeMenu_);
  toolAction_.setMenu(&toolMenu_);

  reloadConfig();
}

MozcEngine::~MozcEngine() {}

void MozcEngine::setConfig(const RawConfig &config) {
  config_.load(config, true);
  safeSaveAsIni(config_, "conf/mozc.conf");
}

void MozcEngine::reloadConfig() { readAsIni(config_, "conf/mozc.conf"); }
void MozcEngine::activate(const fcitx::InputMethodEntry &,
                          fcitx::InputContextEvent &event) {
  auto ic = event.inputContext();
  auto mozc_state = mozcState(ic);
  mozc_state->FocusIn();
  ic->statusArea().addAction(StatusGroup::InputMethod, &modeAction_);
  ic->statusArea().addAction(StatusGroup::InputMethod, &toolAction_);
}
void MozcEngine::deactivate(const fcitx::InputMethodEntry &,
                            fcitx::InputContextEvent &event) {
  auto ic = event.inputContext();
  auto mozc_state = mozcState(ic);
  mozc_state->FocusOut();
}
void MozcEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &event) {
  auto mozc_state = mozcState(event.inputContext());

  auto &group = instance_->inputMethodManager().currentGroup();
  std::string layout = group.layoutFor(entry.uniqueName());
  if (layout.empty()) {
    layout = group.defaultLayout();
  }

  const bool isJP = (layout == "jp" || stringutils::startsWith(layout, "jp-"));

  if (mozc_state->ProcessKeyEvent(event.rawKey().sym(), event.rawKey().code(),
                                  event.rawKey().states(), isJP,
                                  event.isRelease())) {
    event.filterAndAccept();
  }
}

void MozcEngine::reset(const InputMethodEntry &, InputContextEvent &event) {
  auto mozc_state = mozcState(event.inputContext());
  mozc_state->Reset();
}

void MozcEngine::save() {}

std::string MozcEngine::subMode(const fcitx::InputMethodEntry &,
                                fcitx::InputContext &ic) {
  return modeAction_.longText(&ic);
}

MozcState *MozcEngine::mozcState(InputContext *ic) {
  return ic->propertyFor(&factory_);
}

void MozcEngine::compositionModeUpdated(InputContext *ic) {
  modeAction_.update(ic);
  for (const auto &modeAction : modeActions_) {
    modeAction->update(ic);
  }
}

AddonInstance *MozcEngine::clipboardAddon() { return clipboard(); }
}  // namespace fcitx
<commit_msg>Call gettext for short text label.<commit_after>/*
 * Copyright (C) 2017~2017 by CSSlayer
 * wengxt@gmail.com
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * 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; see the file COPYING. If not,
 * see <http://www.gnu.org/licenses/>.
 */

#include "unix/fcitx5/mozc_engine.h"

#include <fcitx-config/iniparser.h>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/standardpath.h>
#include <fcitx/inputcontext.h>
#include <fcitx/inputcontextmanager.h>
#include <fcitx/inputmethodmanager.h>
#include <fcitx/userinterfacemanager.h>

#include <vector>

#include "base/init_mozc.h"
#include "base/process.h"
#include "unix/fcitx5/mozc_connection.h"
#include "unix/fcitx5/mozc_response_parser.h"

namespace fcitx {

const struct CompositionMode {
  const char *name;
  const char *icon;
  const char *label;
  const char *description;
  mozc::commands::CompositionMode mode;
} kPropCompositionModes[] = {
    {
        "mozc-mode-direct",
        "fcitx-mozc-direct",
        "A",
        N_("Direct"),
        mozc::commands::DIRECT,
    },
    {
        "mozc-mode-hiragana",
        "fcitx-mozc-hiragana",
        "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
        N_("Hiragana"),
        mozc::commands::HIRAGANA,
    },
    {
        "mozc-mode-katakana_full",
        "fcitx-mozc-katakana-full",
        "\xe3\x82\xa2",  // Katakana letter A.
        N_("Full Katakana"),
        mozc::commands::FULL_KATAKANA,
    },
    {

        "mozc-mode-alpha_half",
        "fcitx-mozc-alpha-half",
        "A",
        N_("Half ASCII"),
        mozc::commands::HALF_ASCII,
    },
    {

        "mozc-mode-alpha_full",
        "fcitx-mozc-alpha-full",
        "\xef\xbc\xa1",  // Full width ASCII letter A.
        N_("Full ASCII"),
        mozc::commands::FULL_ASCII,
    },
    {
        "mozc-mode-katakana_half",
        "fcitx-mozc-katakana-half",
        "\xef\xbd\xb1",  // Half width Katakana letter A.
        N_("Half Katakana"),
        mozc::commands::HALF_KATAKANA,
    },
};
const size_t kNumCompositionModes = arraysize(kPropCompositionModes);

std::string MozcModeAction::shortText(InputContext *) const {
  return _("Composition Mode");
}

std::string MozcModeAction::longText(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return _(kPropCompositionModes[mozc_state->GetCompositionMode()].description);
}

std::string MozcModeAction::icon(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return kPropCompositionModes[mozc_state->GetCompositionMode()].icon;
}

MozcModeSubAction::MozcModeSubAction(MozcEngine *engine,
                                     mozc::commands::CompositionMode mode)
    : engine_(engine), mode_(mode) {
  setShortText(_(kPropCompositionModes[mode].description));
  setLongText(_(kPropCompositionModes[mode].description));
  setIcon(kPropCompositionModes[mode].icon);
  setCheckable(true);
}

bool MozcModeSubAction::isChecked(InputContext *ic) const {
  auto mozc_state = engine_->mozcState(ic);
  return mozc_state->GetCompositionMode() == mode_;
}

void MozcModeSubAction::activate(InputContext *ic) {
  auto mozc_state = engine_->mozcState(ic);
  mozc_state->SendCompositionMode(mode_);
}

// This array must correspond with the CompositionMode enum in the
// mozc/session/command.proto file.
static_assert(mozc::commands::NUM_OF_COMPOSITIONS == kNumCompositionModes,
              "number of modes must match");

Instance *Init(Instance *instance) {
  int argc = 1;
  char argv0[] = "fcitx_mozc";
  char *_argv[] = {argv0};
  char **argv = _argv;
  mozc::InitMozc(argv[0], &argc, &argv);
  return instance;
}

MozcEngine::MozcEngine(Instance *instance)
    : instance_(Init(instance)),
      connection_(std::make_unique<MozcConnection>()),
      factory_([this](InputContext &ic) {
        return new MozcState(&ic, connection_->CreateClient(), this);
      }),
      modeAction_(this) {
  for (auto command :
       {mozc::commands::DIRECT, mozc::commands::HIRAGANA,
        mozc::commands::FULL_KATAKANA, mozc::commands::FULL_ASCII,
        mozc::commands::HALF_ASCII, mozc::commands::HALF_KATAKANA}) {
    modeActions_.push_back(std::make_unique<MozcModeSubAction>(this, command));
  }
  instance_->inputContextManager().registerProperty("mozcState", &factory_);
  instance_->userInterfaceManager().registerAction("mozc-mode", &modeAction_);
  instance_->userInterfaceManager().registerAction("mozc-tool", &toolAction_);
  toolAction_.setShortText(_("Tool"));
  toolAction_.setLongText(_("Tool"));
  toolAction_.setIcon("fcitx-mozc-tool");

  int i = 0;
  for (auto &modeAction : modeActions_) {
    instance_->userInterfaceManager().registerAction(
        kPropCompositionModes[i].name, modeAction.get());
    modeMenu_.addAction(modeAction.get());
    i++;
  }

  instance_->userInterfaceManager().registerAction("mozc-tool-config",
                                                   &configToolAction_);
  configToolAction_.setShortText(_("Configuration Tool"));
  configToolAction_.setIcon("fcitx-mozc-tool");
  configToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=config_dialog");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-dict",
                                                   &dictionaryToolAction_);
  dictionaryToolAction_.setShortText(_("Dictionary Tool"));
  dictionaryToolAction_.setIcon("fcitx-mozc-dictionary");
  dictionaryToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=dictionary_tool");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-add",
                                                   &addWordAction_);
  addWordAction_.setShortText(_("Add Word"));
  addWordAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=word_register_dialog");
  });

  instance_->userInterfaceManager().registerAction("mozc-tool-about",
                                                   &aboutAction_);
  aboutAction_.setShortText(_("About Mozc"));
  aboutAction_.connect<SimpleAction::Activated>([](InputContext *) {
    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=about_dialog");
  });

  toolMenu_.addAction(&configToolAction_);
  toolMenu_.addAction(&dictionaryToolAction_);
  toolMenu_.addAction(&addWordAction_);
  toolMenu_.addAction(&aboutAction_);

  modeAction_.setMenu(&modeMenu_);
  toolAction_.setMenu(&toolMenu_);

  reloadConfig();
}

MozcEngine::~MozcEngine() {}

void MozcEngine::setConfig(const RawConfig &config) {
  config_.load(config, true);
  safeSaveAsIni(config_, "conf/mozc.conf");
}

void MozcEngine::reloadConfig() { readAsIni(config_, "conf/mozc.conf"); }
void MozcEngine::activate(const fcitx::InputMethodEntry &,
                          fcitx::InputContextEvent &event) {
  auto ic = event.inputContext();
  auto mozc_state = mozcState(ic);
  mozc_state->FocusIn();
  ic->statusArea().addAction(StatusGroup::InputMethod, &modeAction_);
  ic->statusArea().addAction(StatusGroup::InputMethod, &toolAction_);
}
void MozcEngine::deactivate(const fcitx::InputMethodEntry &,
                            fcitx::InputContextEvent &event) {
  auto ic = event.inputContext();
  auto mozc_state = mozcState(ic);
  mozc_state->FocusOut();
}
void MozcEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &event) {
  auto mozc_state = mozcState(event.inputContext());

  auto &group = instance_->inputMethodManager().currentGroup();
  std::string layout = group.layoutFor(entry.uniqueName());
  if (layout.empty()) {
    layout = group.defaultLayout();
  }

  const bool isJP = (layout == "jp" || stringutils::startsWith(layout, "jp-"));

  if (mozc_state->ProcessKeyEvent(event.rawKey().sym(), event.rawKey().code(),
                                  event.rawKey().states(), isJP,
                                  event.isRelease())) {
    event.filterAndAccept();
  }
}

void MozcEngine::reset(const InputMethodEntry &, InputContextEvent &event) {
  auto mozc_state = mozcState(event.inputContext());
  mozc_state->Reset();
}

void MozcEngine::save() {}

std::string MozcEngine::subMode(const fcitx::InputMethodEntry &,
                                fcitx::InputContext &ic) {
  return modeAction_.longText(&ic);
}

MozcState *MozcEngine::mozcState(InputContext *ic) {
  return ic->propertyFor(&factory_);
}

void MozcEngine::compositionModeUpdated(InputContext *ic) {
  modeAction_.update(ic);
  for (const auto &modeAction : modeActions_) {
    modeAction->update(ic);
  }
}

AddonInstance *MozcEngine::clipboardAddon() { return clipboard(); }
}  // namespace fcitx
<|endoftext|>