<commit_before>#include "client.hh"

#include "color_registry.hh"
#include "context.hh"
#include "buffer_manager.hh"
#include "user_interface.hh"
#include "file.hh"
#include "remote.hh"
#include "client_manager.hh"
#include "window.hh"

namespace Kakoune
{

Client::Client(std::unique_ptr<UserInterface>&& ui,
               std::unique_ptr<Window>&& window,
               SelectionList selections,
               EnvVarMap env_vars,
               String name)
    : m_ui{std::move(ui)}, m_window{std::move(window)},
      m_input_handler{std::move(selections),
                      std::move(name)},
      m_env_vars(env_vars)
{
    context().set_client(*this);
    context().set_window(*m_window);
}

Client::~Client()
{
}

void Client::handle_available_input()
{
    while (m_ui->is_key_available())
    {
        m_input_handler.handle_key(m_ui->get_key());
        m_input_handler.clear_mode_trash();
    }
    context().window().forget_timestamp();
}

void Client::print_status(DisplayLine status_line)
{
    m_status_line = std::move(status_line);
    context().window().forget_timestamp();
}

DisplayLine Client::generate_mode_line() const
{
    auto pos = context().selections().main().cursor();
    auto col = context().buffer()[pos.line].char_count_to(pos.column);

    std::ostringstream oss;
    oss << context().buffer().display_name()
        << " " << (int)pos.line+1 << ":" << (int)col+1;
    if (context().buffer().is_modified())
        oss << " [+]";
    if (m_input_handler.is_recording())
       oss << " [recording (" << m_input_handler.recording_reg() << ")]";
    if (context().buffer().flags() & Buffer::Flags::New)
        oss << " [new file]";
    oss << " [" << m_input_handler.mode_string() << "]" << " - "
        << context().name() << "@[" << Server::instance().session() << "]";
    return { oss.str(), get_color("StatusLine") };
}

void Client::change_buffer(Buffer& buffer)
{
    auto& client_manager = ClientManager::instance();
    client_manager.add_free_window(std::move(m_window),
                                   std::move(context().selections()));
    WindowAndSelections ws = client_manager.get_free_window(buffer);
    m_window = std::move(ws.window);
    context().m_selections = std::move(ws.selections);
    context().set_window(*m_window);
    m_window->set_dimensions(ui().dimensions());
    m_window->hooks().run_hook("WinDisplay", buffer.name(), context());
}

void Client::redraw_ifn()
{
    if (context().window().timestamp() != context().buffer().timestamp())
    {
        CharCoord dimensions = context().ui().dimensions();
        if (dimensions == CharCoord{0,0})
            return;
        context().window().set_dimensions(dimensions);
        context().window().update_display_buffer(context());

        context().ui().draw(context().window().display_buffer(),
                            m_status_line, generate_mode_line());
    }
    context().ui().refresh();
}

static void reload_buffer(Context& context, const String& filename)
{
    CharCoord view_pos = context.window().position();
    ByteCoord cursor_pos = context.selections().main().cursor();
    Buffer* buf = create_buffer_from_file(filename);
    if (not buf)
        return;
    context.change_buffer(*buf);
    context.selections() = SelectionList{ *buf, buf->clamp(cursor_pos)};
    context.window().set_position(view_pos);
    context.print_status({ "'" + buf->display_name() + "' reloaded",
                           get_color("Information") });
}

void Client::check_buffer_fs_timestamp()
{
    Buffer& buffer = context().buffer();
    auto reload = context().options()["autoreload"].get<YesNoAsk>();
    if (not (buffer.flags() & Buffer::Flags::File) or reload == No)
        return;

    const String& filename = buffer.name();
    time_t ts = get_fs_timestamp(filename);
    if (ts == buffer.fs_timestamp())
        return;
    if (reload == Ask)
    {
        CharCoord pos = context().window().dimensions();
        pos.column -= 1;
        m_ui->info_show(
            "reload '" + buffer.display_name() + "' ?",
            "'" + buffer.display_name() + "' was modified externally\n"
            "press r or y to reload, k or n to keep",
            pos, get_color("Information"), MenuStyle::Prompt);

        m_input_handler.on_next_key([this, filename, ts](Key key, Context& context) {
            Buffer* buf = BufferManager::instance().get_buffer_ifp(filename);
            m_ui->info_hide();
            // buffer got deleted while waiting for the key, do nothing
            if (not buf)
                return;
            if (key == 'r' or key == 'y')
                reload_buffer(context, filename);
            else if (key == 'k' or key == 'n')
            {
                buf->set_fs_timestamp(ts);
                print_status({ "'" + buf->display_name() + "' kept",
                               get_color("Information") });
            }
            else
            {
                print_status({ "'" + key_to_str(key) + "' is not a valid choice",
                               get_color("Error") });
                check_buffer_fs_timestamp();
            }
        });
    }
    else
        reload_buffer(context(), filename);
}

const String& Client::get_env_var(const String& name) const
{
    auto it = m_env_vars.find(name);
    static String empty{};
    if (it == m_env_vars.end())
        return empty;
    return it->second;
}

}
<commit_msg>Do not try to reload buffer if the buffer was deleted<commit_after>#include "client.hh"

#include "color_registry.hh"
#include "context.hh"
#include "buffer_manager.hh"
#include "user_interface.hh"
#include "file.hh"
#include "remote.hh"
#include "client_manager.hh"
#include "window.hh"

namespace Kakoune
{

Client::Client(std::unique_ptr<UserInterface>&& ui,
               std::unique_ptr<Window>&& window,
               SelectionList selections,
               EnvVarMap env_vars,
               String name)
    : m_ui{std::move(ui)}, m_window{std::move(window)},
      m_input_handler{std::move(selections),
                      std::move(name)},
      m_env_vars(env_vars)
{
    context().set_client(*this);
    context().set_window(*m_window);
}

Client::~Client()
{
}

void Client::handle_available_input()
{
    while (m_ui->is_key_available())
    {
        m_input_handler.handle_key(m_ui->get_key());
        m_input_handler.clear_mode_trash();
    }
    context().window().forget_timestamp();
}

void Client::print_status(DisplayLine status_line)
{
    m_status_line = std::move(status_line);
    context().window().forget_timestamp();
}

DisplayLine Client::generate_mode_line() const
{
    auto pos = context().selections().main().cursor();
    auto col = context().buffer()[pos.line].char_count_to(pos.column);

    std::ostringstream oss;
    oss << context().buffer().display_name()
        << " " << (int)pos.line+1 << ":" << (int)col+1;
    if (context().buffer().is_modified())
        oss << " [+]";
    if (m_input_handler.is_recording())
       oss << " [recording (" << m_input_handler.recording_reg() << ")]";
    if (context().buffer().flags() & Buffer::Flags::New)
        oss << " [new file]";
    oss << " [" << m_input_handler.mode_string() << "]" << " - "
        << context().name() << "@[" << Server::instance().session() << "]";
    return { oss.str(), get_color("StatusLine") };
}

void Client::change_buffer(Buffer& buffer)
{
    auto& client_manager = ClientManager::instance();
    client_manager.add_free_window(std::move(m_window),
                                   std::move(context().selections()));
    WindowAndSelections ws = client_manager.get_free_window(buffer);
    m_window = std::move(ws.window);
    context().m_selections = std::move(ws.selections);
    context().set_window(*m_window);
    m_window->set_dimensions(ui().dimensions());
    m_window->hooks().run_hook("WinDisplay", buffer.name(), context());
}

void Client::redraw_ifn()
{
    if (context().window().timestamp() != context().buffer().timestamp())
    {
        CharCoord dimensions = context().ui().dimensions();
        if (dimensions == CharCoord{0,0})
            return;
        context().window().set_dimensions(dimensions);
        context().window().update_display_buffer(context());

        context().ui().draw(context().window().display_buffer(),
                            m_status_line, generate_mode_line());
    }
    context().ui().refresh();
}

static void reload_buffer(Context& context, const String& filename)
{
    CharCoord view_pos = context.window().position();
    ByteCoord cursor_pos = context.selections().main().cursor();
    Buffer* buf = create_buffer_from_file(filename);
    if (not buf)
        return;
    context.change_buffer(*buf);
    context.selections() = SelectionList{ *buf, buf->clamp(cursor_pos)};
    context.window().set_position(view_pos);
    context.print_status({ "'" + buf->display_name() + "' reloaded",
                           get_color("Information") });
}

void Client::check_buffer_fs_timestamp()
{
    Buffer& buffer = context().buffer();
    auto reload = context().options()["autoreload"].get<YesNoAsk>();
    if (not (buffer.flags() & Buffer::Flags::File) or reload == No)
        return;

    const String& filename = buffer.name();
    time_t ts = get_fs_timestamp(filename);
    if (ts == InvalidTime or ts == buffer.fs_timestamp())
        return;
    if (reload == Ask)
    {
        CharCoord pos = context().window().dimensions();
        pos.column -= 1;
        m_ui->info_show(
            "reload '" + buffer.display_name() + "' ?",
            "'" + buffer.display_name() + "' was modified externally\n"
            "press r or y to reload, k or n to keep",
            pos, get_color("Information"), MenuStyle::Prompt);

        m_input_handler.on_next_key([this, filename, ts](Key key, Context& context) {
            Buffer* buf = BufferManager::instance().get_buffer_ifp(filename);
            m_ui->info_hide();
            // buffer got deleted while waiting for the key, do nothing
            if (not buf)
                return;
            if (key == 'r' or key == 'y')
                reload_buffer(context, filename);
            else if (key == 'k' or key == 'n')
            {
                buf->set_fs_timestamp(ts);
                print_status({ "'" + buf->display_name() + "' kept",
                               get_color("Information") });
            }
            else
            {
                print_status({ "'" + key_to_str(key) + "' is not a valid choice",
                               get_color("Error") });
                check_buffer_fs_timestamp();
            }
        });
    }
    else
        reload_buffer(context(), filename);
}

const String& Client::get_env_var(const String& name) const
{
    auto it = m_env_vars.find(name);
    static String empty{};
    if (it == m_env_vars.end())
        return empty;
    return it->second;
}

}
<|endoftext|>


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

#include "extensions/renderer/user_script_set_manager.h"

#include "content/public/renderer/render_thread.h"
#include "extensions/common/extension_messages.h"
#include "extensions/renderer/dispatcher.h"
#include "extensions/renderer/user_script_set.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebFrame.h"

namespace extensions {

UserScriptSetManager::UserScriptSetManager(const ExtensionSet* extensions)
    : static_scripts_(extensions), extensions_(extensions) {
  content::RenderThread::Get()->AddObserver(this);
}

UserScriptSetManager::~UserScriptSetManager() {
}

void UserScriptSetManager::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void UserScriptSetManager::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool UserScriptSetManager::OnControlMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

const UserScriptSet* UserScriptSetManager::GetProgrammaticScriptsByExtension(
    const ExtensionId& extension_id) {
  UserScriptSetMap::const_iterator it =
      programmatic_scripts_.find(extension_id);
  return it != programmatic_scripts_.end() ? it->second.get() : NULL;
}

void UserScriptSetManager::GetAllInjections(
    ScopedVector<ScriptInjection>* injections,
    blink::WebFrame* web_frame,
    int tab_id,
    UserScript::RunLocation run_location) {
  static_scripts_.GetInjections(injections, web_frame, tab_id, run_location);
  for (UserScriptSetMap::iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetInjections(injections, web_frame, tab_id, run_location);
  }
}

void UserScriptSetManager::GetAllActiveExtensionIds(
    std::set<std::string>* ids) const {
  DCHECK(ids);
  static_scripts_.GetActiveExtensionIds(ids);
  for (UserScriptSetMap::const_iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetActiveExtensionIds(ids);
  }
}

void UserScriptSetManager::OnUpdateUserScripts(
    base::SharedMemoryHandle shared_memory,
    const ExtensionId& extension_id,
    const std::set<std::string>& changed_extensions) {
  if (!base::SharedMemory::IsHandleValid(shared_memory)) {
    NOTREACHED() << "Bad scripts handle";
    return;
  }

  for (std::set<std::string>::const_iterator iter = changed_extensions.begin();
       iter != changed_extensions.end();
       ++iter) {
    if (!Extension::IdIsValid(*iter)) {
      NOTREACHED() << "Invalid extension id: " << *iter;
      return;
    }
  }

  UserScriptSet* scripts = NULL;
  if (!extension_id.empty()) {
    // The expectation when there is an extensions that "owns" this shared
    // memory region is that it will list itself as the only changed extension.
    CHECK(changed_extensions.size() == 1 &&
          changed_extensions.find(extension_id) != changed_extensions.end());
    if (programmatic_scripts_.find(extension_id) ==
        programmatic_scripts_.end()) {
      scripts = new UserScriptSet(extensions_);
      programmatic_scripts_[extension_id] = make_linked_ptr(scripts);
    } else {
      scripts = programmatic_scripts_[extension_id].get();
    }
  } else {
    scripts = &static_scripts_;
  }
  DCHECK(scripts);

  if (scripts->UpdateUserScripts(shared_memory, changed_extensions)) {
    FOR_EACH_OBSERVER(
        Observer,
        observers_,
        OnUserScriptsUpdated(changed_extensions, scripts->scripts()));
  }
}

}  // namespace extensions
<commit_msg>Account for all extensions case in UserScriptsUpdated message handling<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/renderer/user_script_set_manager.h"

#include "content/public/renderer/render_thread.h"
#include "extensions/common/extension_messages.h"
#include "extensions/renderer/dispatcher.h"
#include "extensions/renderer/user_script_set.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebFrame.h"

namespace extensions {

UserScriptSetManager::UserScriptSetManager(const ExtensionSet* extensions)
    : static_scripts_(extensions), extensions_(extensions) {
  content::RenderThread::Get()->AddObserver(this);
}

UserScriptSetManager::~UserScriptSetManager() {
}

void UserScriptSetManager::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void UserScriptSetManager::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool UserScriptSetManager::OnControlMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

const UserScriptSet* UserScriptSetManager::GetProgrammaticScriptsByExtension(
    const ExtensionId& extension_id) {
  UserScriptSetMap::const_iterator it =
      programmatic_scripts_.find(extension_id);
  return it != programmatic_scripts_.end() ? it->second.get() : NULL;
}

void UserScriptSetManager::GetAllInjections(
    ScopedVector<ScriptInjection>* injections,
    blink::WebFrame* web_frame,
    int tab_id,
    UserScript::RunLocation run_location) {
  static_scripts_.GetInjections(injections, web_frame, tab_id, run_location);
  for (UserScriptSetMap::iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetInjections(injections, web_frame, tab_id, run_location);
  }
}

void UserScriptSetManager::GetAllActiveExtensionIds(
    std::set<std::string>* ids) const {
  DCHECK(ids);
  static_scripts_.GetActiveExtensionIds(ids);
  for (UserScriptSetMap::const_iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetActiveExtensionIds(ids);
  }
}

void UserScriptSetManager::OnUpdateUserScripts(
    base::SharedMemoryHandle shared_memory,
    const ExtensionId& extension_id,
    const std::set<std::string>& changed_extensions) {
  if (!base::SharedMemory::IsHandleValid(shared_memory)) {
    NOTREACHED() << "Bad scripts handle";
    return;
  }

  for (std::set<std::string>::const_iterator iter = changed_extensions.begin();
       iter != changed_extensions.end();
       ++iter) {
    if (!Extension::IdIsValid(*iter)) {
      NOTREACHED() << "Invalid extension id: " << *iter;
      return;
    }
  }

  UserScriptSet* scripts = NULL;
  if (!extension_id.empty()) {
    // The expectation when there is an extensions that "owns" this shared
    // memory region is that it will list itself as the only changed extension.
    CHECK(changed_extensions.size() == 1 &&
          changed_extensions.find(extension_id) != changed_extensions.end());
    if (programmatic_scripts_.find(extension_id) ==
        programmatic_scripts_.end()) {
      scripts = new UserScriptSet(extensions_);
      programmatic_scripts_[extension_id] = make_linked_ptr(scripts);
    } else {
      scripts = programmatic_scripts_[extension_id].get();
    }
  } else {
    scripts = &static_scripts_;
  }
  DCHECK(scripts);

  // If no extensions are included in the set, that indicates that all
  // extensions were updated. Add them all to the set so that observers and
  // individual UserScriptSets don't need to know this detail.
  const std::set<std::string>* effective_extensions = &changed_extensions;
  std::set<std::string> all_extensions;
  if (changed_extensions.empty()) {
    all_extensions = extensions_->GetIDs();
    effective_extensions = &all_extensions;
  }

  if (scripts->UpdateUserScripts(shared_memory, *effective_extensions)) {
    FOR_EACH_OBSERVER(
        Observer,
        observers_,
        OnUserScriptsUpdated(*effective_extensions, scripts->scripts()));
  }
}

}  // namespace extensions
<|endoftext|>


<commit_before>
// This file is part of node-lmdb, the Node.js binding for lmdb
// Copyright (c) 2013-2017 Timur Kristóf
// Licensed to you under the terms of the MIT license
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "node-lmdb.h"

using namespace v8;
using namespace node;

TxnWrap::TxnWrap(MDB_env *env, MDB_txn *txn) {
    this->env = env;
    this->txn = txn;
    this->flags = 0;
}

TxnWrap::~TxnWrap() {
    // Close if not closed already
    if (this->txn) {
        mdb_txn_abort(txn);
        this->removeFromEnvWrap();
    }
}

void TxnWrap::removeFromEnvWrap() {
    if (this->ew) {
        if (this->ew->currentWriteTxn == this) {
            this->ew->currentWriteTxn = nullptr;
        }
        else {
            auto it = std::find(ew->readTxns.begin(), ew->readTxns.end(), this);
            if (it != ew->readTxns.end()) {
                ew->readTxns.erase(it);
            }
        }

        this->ew->Unref();
        this->ew = nullptr;
    }
}

NAN_METHOD(TxnWrap::ctor) {
    Nan::HandleScope scope;

    EnvWrap *ew = Nan::ObjectWrap::Unwrap<EnvWrap>(info[0]->ToObject());
    int flags = 0;

    if (info[1]->IsObject()) {
        Local<Object> options = info[1]->ToObject();

        // Get flags from options

        setFlagFromValue(&flags, MDB_RDONLY, "readOnly", false, options);
    }

    // Check existence of current write transaction
    if (0 == (flags & MDB_RDONLY) && ew->currentWriteTxn != nullptr) {
        return Nan::ThrowError("You have already opened a write transaction in the current process, can't open a second one.");
    }

    MDB_txn *txn;
    int rc = mdb_txn_begin(ew->env, nullptr, flags, &txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }

    TxnWrap* tw = new TxnWrap(ew->env, txn);
    tw->flags = flags;
    tw->ew = ew;
    tw->ew->Ref();
    tw->Wrap(info.This());

    // Set the current write transaction
    if (0 == (flags & MDB_RDONLY)) {
        ew->currentWriteTxn = tw;
    }
    else {
        ew->readTxns.push_back(tw);
    }

    return info.GetReturnValue().Set(info.This());
}

NAN_METHOD(TxnWrap::commit) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_commit(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::abort) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_abort(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;
}

NAN_METHOD(TxnWrap::reset) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_reset(tw->txn);
}

NAN_METHOD(TxnWrap::renew) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_renew(tw->txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::getCommon(Nan::NAN_METHOD_ARGS_TYPE info, Local<Value> (*successFunc)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 2 && info.Length() != 3) {
        return Nan::ThrowError("Invalid number of arguments to cursor.get");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    MDB_val key, oldkey, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[2], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Bookkeeping for old key so that we can free it even if key will point inside LMDB
    oldkey.mv_data = key.mv_data;
    oldkey.mv_size = key.mv_size;

    int rc = mdb_get(tw->txn, dw->dbi, &key, &data);

    if (freeKey) {
        freeKey(oldkey);
    }

    if (rc == MDB_NOTFOUND) {
        return info.GetReturnValue().Set(Nan::Null());
    }
    else if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
    else {
      return info.GetReturnValue().Set(successFunc(data));
    }
}

NAN_METHOD(TxnWrap::getString) {
    return getCommon(info, valToString);
}

NAN_METHOD(TxnWrap::getStringUnsafe) {
    return getCommon(info, valToStringUnsafe);
}

NAN_METHOD(TxnWrap::getBinary) {
    return getCommon(info, valToBinary);
}

NAN_METHOD(TxnWrap::getBinaryUnsafe) {
    return getCommon(info, valToBinaryUnsafe);
}

NAN_METHOD(TxnWrap::getNumber) {
    return getCommon(info, valToNumber);
}

NAN_METHOD(TxnWrap::getBoolean) {
    return getCommon(info, valToBoolean);
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::putCommon(Nan::NAN_METHOD_ARGS_TYPE info, void (*fillFunc)(Nan::NAN_METHOD_ARGS_TYPE info, MDB_val&), void (*freeData)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 3 && info.Length() != 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.put");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int flags = 0;
    MDB_val key, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[3], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    if (!info[3]->IsNull() && !info[3]->IsUndefined() && info[3]->IsObject()) {
        auto options = info[3]->ToObject();
        setFlagFromValue(&flags, MDB_NODUPDATA, "noDupData", false, options);
        setFlagFromValue(&flags, MDB_NOOVERWRITE, "noOverwrite", false, options);
        setFlagFromValue(&flags, MDB_APPEND, "append", false, options);
        setFlagFromValue(&flags, MDB_APPENDDUP, "appendDup", false, options);

        // NOTE: does not make sense to support MDB_RESERVE, because it wouldn't save the memcpy from V8 to lmdb
    }

    fillFunc(info, data);

    int rc = mdb_put(tw->txn, dw->dbi, &key, &data, flags);
    if (freeKey) {
        freeKey(key);
    }
    freeData(data);

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::putString) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        CustomExternalStringResource::writeTo(info[2]->ToString(), &data);
    }, [](MDB_val &data) -> void {
        delete[] (uint16_t*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBinary) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = node::Buffer::Length(info[2]);
        data.mv_data = node::Buffer::Data(info[2]);
    }, [](MDB_val &) -> void {
        // The data is owned by the node::Buffer so we don't need to free it.
    });
}

NAN_METHOD(TxnWrap::putNumber) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new double;
        auto numberLocal = Nan::To<v8::Number>(info[2]).ToLocalChecked();
        *((double*)data.mv_data) = numberLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (double*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBoolean) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new bool;
        auto booleanLocal = Nan::To<v8::Boolean>(info[2]).ToLocalChecked();
        *((bool*)data.mv_data) = booleanLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (bool*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::del) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    MDB_val key;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[2], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Set data if dupSort true and data given
    MDB_val data;
    Local<Value> dataHandle = info[2];
    bool freeData = false;

    if ((dw->flags & MDB_DUPSORT) && !(dataHandle->IsUndefined())) {
        if (dataHandle->IsString()) {
            CustomExternalStringResource::writeTo(dataHandle->ToString(), &data);
            freeData = true;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            data.mv_size = node::Buffer::Length(dataHandle);
            data.mv_data = node::Buffer::Data(dataHandle);
            freeData = true;
        }
        else if (dataHandle->IsNumber()) {
            auto numberLocal = Nan::To<v8::Number>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new double;
            *reinterpret_cast<double*>(data.mv_data) = numberLocal->Value();
            freeData = true;
        }
        else if (dataHandle->IsBoolean()) {
            auto booleanLocal = Nan::To<v8::Boolean>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new bool;
            *reinterpret_cast<bool*>(data.mv_data) = booleanLocal->Value();
            freeData = true;
        }
        else {
            Nan::ThrowError("Invalid data type.");
        }
    }

    int rc = mdb_del(tw->txn, dw->dbi, &key, freeData ? &data : nullptr);

    if (freeKey) {
        freeKey(key);
    }

    if (freeData) {
        if (dataHandle->IsString()) {
            delete[] (uint16_t*)data.mv_data;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            // I think the data is owned by the node::Buffer so we don't need to free it - need to clarify
        }
        else if (dataHandle->IsNumber()) {
            delete (double*)data.mv_data;
        }
        else if (dataHandle->IsBoolean()) {
            delete (bool*)data.mv_data;
        }
    }

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}
<commit_msg>fix cursor.del data/options mixup<commit_after>
// This file is part of node-lmdb, the Node.js binding for lmdb
// Copyright (c) 2013-2017 Timur Kristóf
// Licensed to you under the terms of the MIT license
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "node-lmdb.h"

using namespace v8;
using namespace node;

TxnWrap::TxnWrap(MDB_env *env, MDB_txn *txn) {
    this->env = env;
    this->txn = txn;
    this->flags = 0;
}

TxnWrap::~TxnWrap() {
    // Close if not closed already
    if (this->txn) {
        mdb_txn_abort(txn);
        this->removeFromEnvWrap();
    }
}

void TxnWrap::removeFromEnvWrap() {
    if (this->ew) {
        if (this->ew->currentWriteTxn == this) {
            this->ew->currentWriteTxn = nullptr;
        }
        else {
            auto it = std::find(ew->readTxns.begin(), ew->readTxns.end(), this);
            if (it != ew->readTxns.end()) {
                ew->readTxns.erase(it);
            }
        }

        this->ew->Unref();
        this->ew = nullptr;
    }
}

NAN_METHOD(TxnWrap::ctor) {
    Nan::HandleScope scope;

    EnvWrap *ew = Nan::ObjectWrap::Unwrap<EnvWrap>(info[0]->ToObject());
    int flags = 0;

    if (info[1]->IsObject()) {
        Local<Object> options = info[1]->ToObject();

        // Get flags from options

        setFlagFromValue(&flags, MDB_RDONLY, "readOnly", false, options);
    }

    // Check existence of current write transaction
    if (0 == (flags & MDB_RDONLY) && ew->currentWriteTxn != nullptr) {
        return Nan::ThrowError("You have already opened a write transaction in the current process, can't open a second one.");
    }

    MDB_txn *txn;
    int rc = mdb_txn_begin(ew->env, nullptr, flags, &txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }

    TxnWrap* tw = new TxnWrap(ew->env, txn);
    tw->flags = flags;
    tw->ew = ew;
    tw->ew->Ref();
    tw->Wrap(info.This());

    // Set the current write transaction
    if (0 == (flags & MDB_RDONLY)) {
        ew->currentWriteTxn = tw;
    }
    else {
        ew->readTxns.push_back(tw);
    }

    return info.GetReturnValue().Set(info.This());
}

NAN_METHOD(TxnWrap::commit) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_commit(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::abort) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_abort(tw->txn);
    tw->removeFromEnvWrap();
    tw->txn = nullptr;
}

NAN_METHOD(TxnWrap::reset) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    mdb_txn_reset(tw->txn);
}

NAN_METHOD(TxnWrap::renew) {
    Nan::HandleScope scope;

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int rc = mdb_txn_renew(tw->txn);
    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::getCommon(Nan::NAN_METHOD_ARGS_TYPE info, Local<Value> (*successFunc)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 2 && info.Length() != 3) {
        return Nan::ThrowError("Invalid number of arguments to cursor.get");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    MDB_val key, oldkey, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[2], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Bookkeeping for old key so that we can free it even if key will point inside LMDB
    oldkey.mv_data = key.mv_data;
    oldkey.mv_size = key.mv_size;

    int rc = mdb_get(tw->txn, dw->dbi, &key, &data);

    if (freeKey) {
        freeKey(oldkey);
    }

    if (rc == MDB_NOTFOUND) {
        return info.GetReturnValue().Set(Nan::Null());
    }
    else if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
    else {
      return info.GetReturnValue().Set(successFunc(data));
    }
}

NAN_METHOD(TxnWrap::getString) {
    return getCommon(info, valToString);
}

NAN_METHOD(TxnWrap::getStringUnsafe) {
    return getCommon(info, valToStringUnsafe);
}

NAN_METHOD(TxnWrap::getBinary) {
    return getCommon(info, valToBinary);
}

NAN_METHOD(TxnWrap::getBinaryUnsafe) {
    return getCommon(info, valToBinaryUnsafe);
}

NAN_METHOD(TxnWrap::getNumber) {
    return getCommon(info, valToNumber);
}

NAN_METHOD(TxnWrap::getBoolean) {
    return getCommon(info, valToBoolean);
}

Nan::NAN_METHOD_RETURN_TYPE TxnWrap::putCommon(Nan::NAN_METHOD_ARGS_TYPE info, void (*fillFunc)(Nan::NAN_METHOD_ARGS_TYPE info, MDB_val&), void (*freeData)(MDB_val&)) {
    Nan::HandleScope scope;

    if (info.Length() != 3 && info.Length() != 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.put");
    }

    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    int flags = 0;
    MDB_val key, data;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], info[3], dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    if (!info[3]->IsNull() && !info[3]->IsUndefined() && info[3]->IsObject()) {
        auto options = info[3]->ToObject();
        setFlagFromValue(&flags, MDB_NODUPDATA, "noDupData", false, options);
        setFlagFromValue(&flags, MDB_NOOVERWRITE, "noOverwrite", false, options);
        setFlagFromValue(&flags, MDB_APPEND, "append", false, options);
        setFlagFromValue(&flags, MDB_APPENDDUP, "appendDup", false, options);

        // NOTE: does not make sense to support MDB_RESERVE, because it wouldn't save the memcpy from V8 to lmdb
    }

    fillFunc(info, data);

    int rc = mdb_put(tw->txn, dw->dbi, &key, &data, flags);
    if (freeKey) {
        freeKey(key);
    }
    freeData(data);

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}

NAN_METHOD(TxnWrap::putString) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        CustomExternalStringResource::writeTo(info[2]->ToString(), &data);
    }, [](MDB_val &data) -> void {
        delete[] (uint16_t*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBinary) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = node::Buffer::Length(info[2]);
        data.mv_data = node::Buffer::Data(info[2]);
    }, [](MDB_val &) -> void {
        // The data is owned by the node::Buffer so we don't need to free it.
    });
}

NAN_METHOD(TxnWrap::putNumber) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new double;
        auto numberLocal = Nan::To<v8::Number>(info[2]).ToLocalChecked();
        *((double*)data.mv_data) = numberLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (double*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::putBoolean) {
    return putCommon(info, [](Nan::NAN_METHOD_ARGS_TYPE info, MDB_val &data) -> void {
        data.mv_size = sizeof(double);
        data.mv_data = new bool;
        auto booleanLocal = Nan::To<v8::Boolean>(info[2]).ToLocalChecked();
        *((bool*)data.mv_data) = booleanLocal->Value();
    }, [](MDB_val &data) -> void {
        delete (bool*)data.mv_data;
    });
}

NAN_METHOD(TxnWrap::del) {
    Nan::HandleScope scope;

    // Check argument count
    auto argCount = info.Length();
    if (argCount < 2 || argCount > 4) {
        return Nan::ThrowError("Invalid number of arguments to cursor.del, should be: (a) <dbi>, <key> (b) <dbi>, <key>, <options> (c) <dbi>, <key>, <data> (d) <dbi>, <key>, <data>, <options>");
    }

    // Unwrap native objects
    TxnWrap *tw = Nan::ObjectWrap::Unwrap<TxnWrap>(info.This());
    DbiWrap *dw = Nan::ObjectWrap::Unwrap<DbiWrap>(info[0]->ToObject());

    if (!tw->txn) {
        return Nan::ThrowError("The transaction is already closed.");
    }

    // Take care of options object and data handle
    Local<Value> options;
    Local<Value> dataHandle;

    if (argCount == 4) {
        options = info[3];
        dataHandle = info[2];
    }
    else if (argCount == 3) {
        if (info[2]->IsObject()) {
            options = info[2];
            dataHandle = Nan::Undefined();
        }
        else {
            options = Nan::Undefined();
            dataHandle = info[2];
        }
    }
    else if (argCount == 2) {
        options = Nan::Undefined();
        dataHandle = Nan::Undefined();
    }
    else {
        return Nan::ThrowError("Unknown arguments to cursor.del, this could be a node-lmdb bug!");
    }

    MDB_val key;
    bool keyIsValid;
    auto keyType = inferAndValidateKeyType(info[1], options, dw->keyType, keyIsValid);
    if (!keyIsValid) {
        // inferAndValidateKeyType already threw an error
        return;
    }
    auto freeKey = argToKey(info[1], key, keyType, keyIsValid);
    if (!keyIsValid) {
        // argToKey already threw an error
        return;
    }

    // Set data if dupSort true and data given
    MDB_val data;
    bool freeData = false;

    if ((dw->flags & MDB_DUPSORT) && !(dataHandle->IsUndefined())) {
        if (dataHandle->IsString()) {
            CustomExternalStringResource::writeTo(dataHandle->ToString(), &data);
            freeData = true;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            data.mv_size = node::Buffer::Length(dataHandle);
            data.mv_data = node::Buffer::Data(dataHandle);
            freeData = true;
        }
        else if (dataHandle->IsNumber()) {
            auto numberLocal = Nan::To<v8::Number>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new double;
            *reinterpret_cast<double*>(data.mv_data) = numberLocal->Value();
            freeData = true;
        }
        else if (dataHandle->IsBoolean()) {
            auto booleanLocal = Nan::To<v8::Boolean>(dataHandle).ToLocalChecked();
            data.mv_size = sizeof(double);
            data.mv_data = new bool;
            *reinterpret_cast<bool*>(data.mv_data) = booleanLocal->Value();
            freeData = true;
        }
        else {
            Nan::ThrowError("Invalid data type.");
        }
    }

    int rc = mdb_del(tw->txn, dw->dbi, &key, freeData ? &data : nullptr);

    if (freeKey) {
        freeKey(key);
    }

    if (freeData) {
        if (dataHandle->IsString()) {
            delete[] (uint16_t*)data.mv_data;
        }
        else if (node::Buffer::HasInstance(dataHandle)) {
            // I think the data is owned by the node::Buffer so we don't need to free it - need to clarify
        }
        else if (dataHandle->IsNumber()) {
            delete (double*)data.mv_data;
        }
        else if (dataHandle->IsBoolean()) {
            delete (bool*)data.mv_data;
        }
    }

    if (rc != 0) {
        return Nan::ThrowError(mdb_strerror(rc));
    }
}
<|endoftext|>


<commit_before>/*
 * type.cc
 * Copyright (C) 2016 romgrk <romgrk@Romgrk-ARCH>
 *
 * Distributed under terms of the GPL license.
 */

#include "gi.h"
#include "type.h"
#include "util.h"
#include "debug.h"

using v8::FunctionTemplate;
using v8::Persistent;

namespace GNodeJS {

void ClassDestroyed(const v8::WeakCallbackInfo<GIBaseInfo> &info) {
    GIBaseInfo *gi_info = info.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);
    void *type_data = g_type_get_qdata (gtype, GNodeJS::template_quark());

    Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) type_data;
    delete persistent;

    g_type_set_qdata (gtype, GNodeJS::template_quark(), NULL);
    g_base_info_unref (gi_info);
}

char *GetInfoName (GIBaseInfo* info) {
    const char* info_name = g_base_info_get_name (info);

    if (info_name == NULL)
        return g_strdup ("(NULL)");

    char* name = g_strdup (info_name);

    GIBaseInfo *parent;
    while ((parent = g_base_info_get_container (info)) != NULL) {
        char *new_name = g_strconcat (g_base_info_get_name(parent), ".", name, NULL);
        g_free (name);
        name = new_name;
    }

    char *new_name = g_strconcat (g_base_info_get_namespace(info), ".", name, NULL);
    g_free (name);
    name = new_name;

    return name;
}

char *GetTypeName (GITypeInfo *type_info) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
            return g_strdup("Boolean");

        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT8:
        case GI_TYPE_TAG_UINT16:
        case GI_TYPE_TAG_UINT32:
        case GI_TYPE_TAG_UINT64:
        case GI_TYPE_TAG_FLOAT:
        case GI_TYPE_TAG_DOUBLE:
            return g_strdup("Number");

        case GI_TYPE_TAG_GTYPE:
            return g_strdup("GType");

        case GI_TYPE_TAG_UNICHAR:
            return g_strdup("Char");

        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
            return g_strdup("String");

        case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *info = g_type_info_get_interface (type_info);
            auto result = g_strdup_printf("%s.%s",
                    g_base_info_get_namespace(info), g_base_info_get_name(info));
            g_base_info_unref (info);
            return result;
        }

        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        {
            GITypeInfo *elem_info = g_type_info_get_param_type(type_info, 0);
            auto elem_name = GetTypeName (elem_info);
            auto result = g_strdup_printf("%s[]", elem_name);

            g_base_info_unref(elem_info);
            g_free(elem_name);

            return result;
        }

        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
        case GI_TYPE_TAG_VOID:
        default:
            return g_strdup(g_type_tag_to_string(type_tag));
    }
}

gsize GetTypeSize (GITypeInfo *type_info) {
    gsize size = 0;

    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_UINT8:
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_UINT16:
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_UINT32:
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT64:
        case GI_TYPE_TAG_FLOAT:
        case GI_TYPE_TAG_DOUBLE:
        case GI_TYPE_TAG_GTYPE:
        case GI_TYPE_TAG_UNICHAR:
        {
            size = GetTypeTagSize (type_tag);
            break;
        }

        case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *info;
            GIInfoType info_type;

            info = g_type_info_get_interface (type_info);
            info_type = g_base_info_get_type (info);

            switch (info_type) {
                case GI_INFO_TYPE_STRUCT:
                    if (g_type_info_is_pointer (type_info)) {
                        size = sizeof (gpointer);
                    } else {
                        size = g_struct_info_get_size ( (GIStructInfo *) info);
                    }
                    break;
                case GI_INFO_TYPE_UNION:
                    if (g_type_info_is_pointer (type_info)) {
                        size = sizeof (gpointer);
                    } else {
                        size = g_union_info_get_size ( (GIUnionInfo *) info);
                    }
                    break;
                case GI_INFO_TYPE_ENUM:
                case GI_INFO_TYPE_FLAGS:
                    if (g_type_info_is_pointer (type_info)) {
                        size = sizeof (gpointer);
                    } else {
                        GITypeTag type_tag;

                        type_tag = g_enum_info_get_storage_type ( (GIEnumInfo *) info);
                        size = GetTypeTagSize (type_tag);
                    }
                    break;
                case GI_INFO_TYPE_BOXED:
                case GI_INFO_TYPE_OBJECT:
                case GI_INFO_TYPE_INTERFACE:
                case GI_INFO_TYPE_CALLBACK:
                    size = sizeof (gpointer);
                    break;
                case GI_INFO_TYPE_VFUNC:
                case GI_INFO_TYPE_FUNCTION:
                case GI_INFO_TYPE_CONSTANT:
                case GI_INFO_TYPE_VALUE:
                case GI_INFO_TYPE_SIGNAL:
                case GI_INFO_TYPE_PROPERTY:
                case GI_INFO_TYPE_FIELD:
                case GI_INFO_TYPE_ARG:
                case GI_INFO_TYPE_TYPE:
                case GI_INFO_TYPE_INVALID:
                case GI_INFO_TYPE_UNRESOLVED:
                default:
                    printf("info type: %s\n", g_info_type_to_string(info_type));
                    g_assert_not_reached();
                    break;
            }

            g_base_info_unref (info);
            break;
        }
        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_VOID:
        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
            size = sizeof(void*);
            break;
    }

    return size;
}

gsize GetTypeTagSize (GITypeTag type_tag) {
    gsize size = 0;

    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
            size = sizeof (gboolean);
            break;
        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_UINT8:
            size = sizeof (gint8);
            break;
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_UINT16:
            size = sizeof (gint16);
            break;
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_UINT32:
            size = sizeof (gint32);
            break;
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT64:
            size = sizeof (gint64);
            break;
        case GI_TYPE_TAG_FLOAT:
            size = sizeof (gfloat);
            break;
        case GI_TYPE_TAG_DOUBLE:
            size = sizeof (gdouble);
            break;
        case GI_TYPE_TAG_GTYPE:
            size = sizeof (GType);
            break;
        case GI_TYPE_TAG_UNICHAR:
            size = sizeof (gunichar);
            break;
        case GI_TYPE_TAG_VOID:
        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_INTERFACE:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
            g_assert_not_reached ();
    }

    return size;
}

GITypeTag GetStorageType (GITypeInfo *type_info) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    if (type_tag == GI_TYPE_TAG_INTERFACE) {
        GIBaseInfo *interface = g_type_info_get_interface (type_info);
        switch (g_base_info_get_type (interface)) {
            case GI_INFO_TYPE_ENUM:
            case GI_INFO_TYPE_FLAGS:
                type_tag = g_enum_info_get_storage_type ((GIEnumInfo *)interface);
                break;
            default:
                /* FIXME: we might have something to do for other types */
                break;
        }
        g_base_info_unref (interface);
    }
    return type_tag;
}

};

<commit_msg>type.cc: reimplement type size functions<commit_after>/*
 * type.cc
 * Copyright (C) 2016 romgrk <romgrk@Romgrk-ARCH>
 *
 * Distributed under terms of the GPL license.
 */

#include "gi.h"
#include "type.h"
#include "util.h"
#include "debug.h"

using v8::FunctionTemplate;
using v8::Persistent;

namespace GNodeJS {

void ClassDestroyed(const v8::WeakCallbackInfo<GIBaseInfo> &info) {
    GIBaseInfo *gi_info = info.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);
    void *type_data = g_type_get_qdata (gtype, GNodeJS::template_quark());

    Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) type_data;
    delete persistent;

    g_type_set_qdata (gtype, GNodeJS::template_quark(), NULL);
    g_base_info_unref (gi_info);
}

char *GetInfoName (GIBaseInfo* info) {
    const char* info_name = g_base_info_get_name (info);

    if (info_name == NULL)
        return g_strdup ("(NULL)");

    char* name = g_strdup (info_name);

    GIBaseInfo *parent;
    while ((parent = g_base_info_get_container (info)) != NULL) {
        char *new_name = g_strconcat (g_base_info_get_name(parent), ".", name, NULL);
        g_free (name);
        name = new_name;
    }

    char *new_name = g_strconcat (g_base_info_get_namespace(info), ".", name, NULL);
    g_free (name);
    name = new_name;

    return name;
}

char *GetTypeName (GITypeInfo *type_info) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
            return g_strdup("Boolean");

        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT8:
        case GI_TYPE_TAG_UINT16:
        case GI_TYPE_TAG_UINT32:
        case GI_TYPE_TAG_UINT64:
        case GI_TYPE_TAG_FLOAT:
        case GI_TYPE_TAG_DOUBLE:
            return g_strdup("Number");

        case GI_TYPE_TAG_GTYPE:
            return g_strdup("GType");

        case GI_TYPE_TAG_UNICHAR:
            return g_strdup("Char");

        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
            return g_strdup("String");

        case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *info = g_type_info_get_interface (type_info);
            auto result = g_strdup_printf("%s.%s",
                    g_base_info_get_namespace(info), g_base_info_get_name(info));
            g_base_info_unref (info);
            return result;
        }

        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        {
            GITypeInfo *elem_info = g_type_info_get_param_type(type_info, 0);
            auto elem_name = GetTypeName (elem_info);
            auto result = g_strdup_printf("%s[]", elem_name);

            g_base_info_unref(elem_info);
            g_free(elem_name);

            return result;
        }

        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
        case GI_TYPE_TAG_VOID:
        default:
            return g_strdup(g_type_tag_to_string(type_tag));
    }
}

gsize GetTypeSize (GITypeInfo *type_info) {
    gsize size = 0;

    GITypeTag type_tag = g_type_info_get_tag (type_info);

    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_UINT8:
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_UINT16:
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_UINT32:
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT64:
        case GI_TYPE_TAG_FLOAT:
        case GI_TYPE_TAG_DOUBLE:
        case GI_TYPE_TAG_GTYPE:
        case GI_TYPE_TAG_UNICHAR:
        {
            size = GetTypeTagSize (type_tag);
            break;
        }

        case GI_TYPE_TAG_INTERFACE:
        {
            GIBaseInfo *info;
            GIInfoType info_type;

            info = g_type_info_get_interface (type_info);
            info_type = g_base_info_get_type (info);

            size = sizeof (gpointer);

            switch (info_type) {
                case GI_INFO_TYPE_STRUCT:
                    if (!g_type_info_is_pointer (type_info)) {
                        size = g_struct_info_get_size ( (GIStructInfo *) info);
                    }
                    break;
                case GI_INFO_TYPE_UNION:
                    if (!g_type_info_is_pointer (type_info)) {
                        size = g_union_info_get_size ( (GIUnionInfo *) info);
                    }
                    break;
                case GI_INFO_TYPE_ENUM:
                case GI_INFO_TYPE_FLAGS:
                    if (!g_type_info_is_pointer (type_info)) {
                        size = GetTypeTagSize (g_enum_info_get_storage_type ( (GIEnumInfo *) info));
                    }
                    break;
                case GI_INFO_TYPE_BOXED:
                case GI_INFO_TYPE_OBJECT:
                case GI_INFO_TYPE_INTERFACE:
                case GI_INFO_TYPE_CALLBACK:
                    break;
                case GI_INFO_TYPE_VFUNC:
                case GI_INFO_TYPE_FUNCTION:
                case GI_INFO_TYPE_CONSTANT:
                case GI_INFO_TYPE_VALUE:
                case GI_INFO_TYPE_SIGNAL:
                case GI_INFO_TYPE_PROPERTY:
                case GI_INFO_TYPE_FIELD:
                case GI_INFO_TYPE_ARG:
                case GI_INFO_TYPE_TYPE:
                case GI_INFO_TYPE_INVALID:
                case GI_INFO_TYPE_UNRESOLVED:
                default:
                    printf("info type: %s\n", g_info_type_to_string(info_type));
                    g_assert_not_reached();
                    break;
            }

            g_base_info_unref (info);
            break;
        }
        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_VOID:
        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
            size = sizeof(gpointer);
            break;
    }

    return size;
}

gsize GetTypeTagSize (GITypeTag type_tag) {
    switch (type_tag) {
        case GI_TYPE_TAG_BOOLEAN:
            return sizeof (gboolean);
            break;
        case GI_TYPE_TAG_INT8:
        case GI_TYPE_TAG_UINT8:
            return sizeof (gint8);
            break;
        case GI_TYPE_TAG_INT16:
        case GI_TYPE_TAG_UINT16:
            return sizeof (gint16);
            break;
        case GI_TYPE_TAG_INT32:
        case GI_TYPE_TAG_UINT32:
            return sizeof (gint32);
            break;
        case GI_TYPE_TAG_INT64:
        case GI_TYPE_TAG_UINT64:
            return sizeof (gint64);
            break;
        case GI_TYPE_TAG_FLOAT:
            return sizeof (gfloat);
            break;
        case GI_TYPE_TAG_DOUBLE:
            return sizeof (gdouble);
            break;
        case GI_TYPE_TAG_GTYPE:
            return sizeof (GType);
            break;
        case GI_TYPE_TAG_UNICHAR:
            return sizeof (gunichar);
            break;
        case GI_TYPE_TAG_VOID:
        case GI_TYPE_TAG_UTF8:
        case GI_TYPE_TAG_FILENAME:
        case GI_TYPE_TAG_ARRAY:
        case GI_TYPE_TAG_INTERFACE:
        case GI_TYPE_TAG_GLIST:
        case GI_TYPE_TAG_GSLIST:
        case GI_TYPE_TAG_GHASH:
        case GI_TYPE_TAG_ERROR:
            g_assert_not_reached ();
    }

    return 0;
}

GITypeTag GetStorageType (GITypeInfo *type_info) {
    GITypeTag type_tag = g_type_info_get_tag (type_info);

    if (type_tag == GI_TYPE_TAG_INTERFACE) {
        GIBaseInfo *interface = g_type_info_get_interface (type_info);
        GIInfoType interface_type = g_base_info_get_type (interface);

        if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS)
            type_tag = g_enum_info_get_storage_type ((GIEnumInfo *)interface);

        g_base_info_unref (interface);
    }

    return type_tag;
}

};

<|endoftext|>


<commit_before>/*
 * ukf.cpp
 *
 *  Created on: Apr 6, 2017
 *  Author: ramiz
 */

#include <iostream>
#include <cmath>
#include "ukf.h"

UKF::UKF() {
  //TODO
}

UKF::~UKF() {
  //TODO
}

void UKF::Init() {

}

void UKF::GenerateSigmaPoints(MatrixXd * Xsig_out) {
  //set state dimension
  int n_x = 5;
  //set augmented state dimension
  int n_aug = 7;

  //Process noise standard deviation longitudinal acceleration in m/s^2
  double std_a = 0.2;

  //Process noise standard deviation yaw acceleration in rad/s^2
  double std_yawdd = 0.2;

  //Process noise variance longitudinal acceleration
  double variance_a = std::pow(std_a, 2);

  //Process noise variance yaw acceleration
  double variance_yawdd = std::pow(std_yawdd, 2);

  //set noise covariance matrix
  MatrixXd Q = MatrixXd::Zero(2, 2);
  Q <<    variance_a, 0,
          0, variance_yawdd;

  //define spreading parameter lamda (design parameter of UKF)
  double lambda = 3 - n_aug;

  //set example state vector
  VectorXd x = VectorXd(n_x);
  x << 5.7441,
      1.3800,
      2.2049,
      0.5015,
      0.3528;

  //set example covariance matrix
  MatrixXd P = MatrixXd(n_x, n_x);
  P <<     0.0043,   -0.0013,    0.0030,   -0.0022,   -0.0020,
          -0.0013,    0.0077,    0.0011,    0.0071,    0.0060,
           0.0030,    0.0011,    0.0054,    0.0007,    0.0008,
          -0.0022,    0.0071,    0.0007,    0.0098,    0.0100,
          -0.0020,    0.0060,    0.0008,    0.0100,    0.0123;

  //create augmented mean vector
  VectorXd x_aug = VectorXd::Zero(n_aug);
  //set augmented mean vector, considering noise mean is zero
  x_aug.head(5) = x;

  //create augmented covariance matrix with Process Covariance matrix P
  //and process noise covariance matrix Q
  MatrixXd P_aug = MatrixXd::Zero(n_aug, n_aug);
  P_aug.topLeftCorner(n_x, n_x) = P;
  P_aug.bottomRightCorner(2, 2) = Q;

  //calculate total sigma points to generate
  int total_sigma_points = 2 * n_aug + 1;

  //create a sigma point matrix
  MatrixXd Xsigma = MatrixXd(n_aug, total_sigma_points);

  //calculate square root of P_aug by using Cholesky decomposition
  MatrixXd A = P_aug.llt().matrixL();

  //calculate sigma points
  //rule part1: first point is mean x so
  Xsigma.col(0) = x_aug;

  //rule part2: calculate next 1 to n_aug points
  Xsigma.block(0, 1, n_aug, n_aug) = (sqrt(lambda + n_aug) * A).colwise() + x_aug;

  //rule part3: calculate next n_aug to 2n_aug points
  Xsigma.block(0, n_aug + 1, n_aug, n_aug) = ( -1 * sqrt(lambda + n_aug) * A).colwise() + x_aug;

  *Xsig_out = Xsigma;
  /* expected result:
     Xsig_aug =
    5.7441  5.85768   5.7441   5.7441   5.7441   5.7441   5.7441   5.7441  5.63052   5.7441   5.7441   5.7441   5.7441   5.7441   5.7441
      1.38  1.34566  1.52806     1.38     1.38     1.38     1.38     1.38  1.41434  1.23194     1.38     1.38     1.38     1.38     1.38
    2.2049  2.28414  2.24557  2.29582   2.2049   2.2049   2.2049   2.2049  2.12566  2.16423  2.11398   2.2049   2.2049   2.2049   2.2049
    0.5015  0.44339 0.631886 0.516923 0.595227   0.5015   0.5015   0.5015  0.55961 0.371114 0.486077 0.407773   0.5015   0.5015   0.5015
    0.3528 0.299973 0.462123 0.376339  0.48417 0.418721   0.3528   0.3528 0.405627 0.243477 0.329261  0.22143 0.286879   0.3528   0.3528
         0        0        0        0        0        0  0.34641        0        0        0        0        0        0 -0.34641        0
         0        0        0        0        0        0        0  0.34641        0        0        0        0        0        0 -0.34641
  */
}

void UKF::SigmaPointPrediction(MatrixXd* Xsig_out) {
  //set state dimension
  int n_x = 5;
  //set augmented state dimension
  int n_aug = 7;

  //create example sigma point matrix
  MatrixXd Xsig_aug = MatrixXd(n_aug, 2 * n_aug + 1);
  Xsig_aug <<
      5.7441,  5.85768,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.63052,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,
        1.38,  1.34566,  1.52806,     1.38,     1.38,     1.38,     1.38,     1.38,   1.41434,  1.23194,     1.38,     1.38,     1.38,     1.38,     1.38,
      2.2049,  2.28414,  2.24557,  2.29582,   2.2049,   2.2049,   2.2049,   2.2049,   2.12566,  2.16423,  2.11398,   2.2049,   2.2049,   2.2049,   2.2049,
      0.5015,  0.44339, 0.631886, 0.516923, 0.595227,   0.5015,   0.5015,   0.5015,   0.55961, 0.371114, 0.486077, 0.407773,   0.5015,   0.5015,   0.5015,
      0.3528, 0.299973, 0.462123, 0.376339,  0.48417, 0.418721,   0.3528,   0.3528,  0.405627, 0.243477, 0.329261,  0.22143, 0.286879,   0.3528,   0.3528,
           0,        0,        0,        0,        0,        0,  0.34641,        0,         0,        0,        0,        0,        0, -0.34641,        0,
           0,        0,        0,        0,        0,        0,        0,  0.34641,         0,        0,        0,        0,        0,        0, -0.34641;

  //create matrix with predicted sigma points as columns
  MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);

  //time diff in secs
  double delta_t = 0.1;

  //predict sigma points
  //avoid division by zero
  //write predicted sigma points into right column
  for(int i = 0; i < Xsig_aug.cols(); ++i) {
//    if (i == 7) {
//      std::cout << "i == " << i << ", x = " << std::endl << Xsig_aug.col(i) << std::endl;
//    }
    Xsig_pred.col(i) = PredictSingleSigmaPoint(Xsig_aug.col(i), delta_t);
  }

  *Xsig_out = Xsig_pred;
}

VectorXd UKF::PredictSingleSigmaPoint(const VectorXd & x_aug, double delta_t) {
  double v = x_aug(2);
  double yaw_angle = x_aug(3);
  double yaw_rate = x_aug(4);
  double noise_longitudinal_a = x_aug(5);
  double noise_yaw_a = x_aug(6);

  //do some common calculations
  double sin_yaw_angle = std::sin(yaw_angle);
  double cos_yaw_angle = std::cos(yaw_angle);
  double delta_t_square = delta_t * delta_t;

  double px_change = 0;
  double py_change = 0;

  if (std::fabs(yaw_rate) > 0.001) {
    //calculations specific to this case
    double c1 = v / yaw_rate;
    double c2 = yaw_angle + yaw_rate * delta_t;
    double sin_c2 = std::sin(c2);
    double cos_c2 = std::cos(c2);

    px_change = (c1 * (sin_c2 - sin_yaw_angle));
    py_change = (c1 * (-cos_c2 + cos_yaw_angle));
  }
  else {
    px_change = (v * cos_yaw_angle * delta_t);
    py_change = (v * sin_yaw_angle * delta_t);
  }

  VectorXd x_change = VectorXd(5);
  x_change << px_change,
              py_change,
              0,
              (yaw_rate * delta_t),
              0;

  VectorXd x_noise = VectorXd(5);
  x_noise <<  (0.5 * delta_t_square * cos_yaw_angle * noise_longitudinal_a),
              (0.5 * delta_t_square * sin_yaw_angle * noise_longitudinal_a),
              (delta_t * noise_longitudinal_a),
              (0.5 * delta_t_square * noise_yaw_a),
              (delta_t * noise_yaw_a);

  //add noise to change in x
  x_change += x_noise;

  //extract state vector x from augmented state vector (contains last 2 elements as noise values after augmentation)
  VectorXd x_old = x_aug.head(5);

  //calculate total change in x state
  VectorXd x_prediction = x_old + x_change;

  return x_prediction;
}

<commit_msg>style: Added expected result for sigma point prediction in comments<commit_after>/*
 * ukf.cpp
 *
 *  Created on: Apr 6, 2017
 *  Author: ramiz
 */

#include <iostream>
#include <cmath>
#include "ukf.h"

UKF::UKF() {
  //TODO
}

UKF::~UKF() {
  //TODO
}

void UKF::Init() {

}

void UKF::GenerateSigmaPoints(MatrixXd * Xsig_out) {
  //set state dimension
  int n_x = 5;
  //set augmented state dimension
  int n_aug = 7;

  //Process noise standard deviation longitudinal acceleration in m/s^2
  double std_a = 0.2;

  //Process noise standard deviation yaw acceleration in rad/s^2
  double std_yawdd = 0.2;

  //Process noise variance longitudinal acceleration
  double variance_a = std::pow(std_a, 2);

  //Process noise variance yaw acceleration
  double variance_yawdd = std::pow(std_yawdd, 2);

  //set noise covariance matrix
  MatrixXd Q = MatrixXd::Zero(2, 2);
  Q <<    variance_a, 0,
          0, variance_yawdd;

  //define spreading parameter lamda (design parameter of UKF)
  double lambda = 3 - n_aug;

  //set example state vector
  VectorXd x = VectorXd(n_x);
  x << 5.7441,
      1.3800,
      2.2049,
      0.5015,
      0.3528;

  //set example covariance matrix
  MatrixXd P = MatrixXd(n_x, n_x);
  P <<     0.0043,   -0.0013,    0.0030,   -0.0022,   -0.0020,
          -0.0013,    0.0077,    0.0011,    0.0071,    0.0060,
           0.0030,    0.0011,    0.0054,    0.0007,    0.0008,
          -0.0022,    0.0071,    0.0007,    0.0098,    0.0100,
          -0.0020,    0.0060,    0.0008,    0.0100,    0.0123;

  //create augmented mean vector
  VectorXd x_aug = VectorXd::Zero(n_aug);
  //set augmented mean vector, considering noise mean is zero
  x_aug.head(5) = x;

  //create augmented covariance matrix with Process Covariance matrix P
  //and process noise covariance matrix Q
  MatrixXd P_aug = MatrixXd::Zero(n_aug, n_aug);
  P_aug.topLeftCorner(n_x, n_x) = P;
  P_aug.bottomRightCorner(2, 2) = Q;

  //calculate total sigma points to generate
  int total_sigma_points = 2 * n_aug + 1;

  //create a sigma point matrix
  MatrixXd Xsigma = MatrixXd(n_aug, total_sigma_points);

  //calculate square root of P_aug by using Cholesky decomposition
  MatrixXd A = P_aug.llt().matrixL();

  //calculate sigma points
  //rule part1: first point is mean x so
  Xsigma.col(0) = x_aug;

  //rule part2: calculate next 1 to n_aug points
  Xsigma.block(0, 1, n_aug, n_aug) = (sqrt(lambda + n_aug) * A).colwise() + x_aug;

  //rule part3: calculate next n_aug to 2n_aug points
  Xsigma.block(0, n_aug + 1, n_aug, n_aug) = ( -1 * sqrt(lambda + n_aug) * A).colwise() + x_aug;

  *Xsig_out = Xsigma;
  /* expected result:
     Xsig_aug =
    5.7441  5.85768   5.7441   5.7441   5.7441   5.7441   5.7441   5.7441  5.63052   5.7441   5.7441   5.7441   5.7441   5.7441   5.7441
      1.38  1.34566  1.52806     1.38     1.38     1.38     1.38     1.38  1.41434  1.23194     1.38     1.38     1.38     1.38     1.38
    2.2049  2.28414  2.24557  2.29582   2.2049   2.2049   2.2049   2.2049  2.12566  2.16423  2.11398   2.2049   2.2049   2.2049   2.2049
    0.5015  0.44339 0.631886 0.516923 0.595227   0.5015   0.5015   0.5015  0.55961 0.371114 0.486077 0.407773   0.5015   0.5015   0.5015
    0.3528 0.299973 0.462123 0.376339  0.48417 0.418721   0.3528   0.3528 0.405627 0.243477 0.329261  0.22143 0.286879   0.3528   0.3528
         0        0        0        0        0        0  0.34641        0        0        0        0        0        0 -0.34641        0
         0        0        0        0        0        0        0  0.34641        0        0        0        0        0        0 -0.34641
  */
}

void UKF::SigmaPointPrediction(MatrixXd* Xsig_out) {
  //set state dimension
  int n_x = 5;
  //set augmented state dimension
  int n_aug = 7;

  //create example sigma point matrix
  MatrixXd Xsig_aug = MatrixXd(n_aug, 2 * n_aug + 1);
  Xsig_aug <<
      5.7441,  5.85768,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.63052,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,   5.7441,
        1.38,  1.34566,  1.52806,     1.38,     1.38,     1.38,     1.38,     1.38,   1.41434,  1.23194,     1.38,     1.38,     1.38,     1.38,     1.38,
      2.2049,  2.28414,  2.24557,  2.29582,   2.2049,   2.2049,   2.2049,   2.2049,   2.12566,  2.16423,  2.11398,   2.2049,   2.2049,   2.2049,   2.2049,
      0.5015,  0.44339, 0.631886, 0.516923, 0.595227,   0.5015,   0.5015,   0.5015,   0.55961, 0.371114, 0.486077, 0.407773,   0.5015,   0.5015,   0.5015,
      0.3528, 0.299973, 0.462123, 0.376339,  0.48417, 0.418721,   0.3528,   0.3528,  0.405627, 0.243477, 0.329261,  0.22143, 0.286879,   0.3528,   0.3528,
           0,        0,        0,        0,        0,        0,  0.34641,        0,         0,        0,        0,        0,        0, -0.34641,        0,
           0,        0,        0,        0,        0,        0,        0,  0.34641,         0,        0,        0,        0,        0,        0, -0.34641;

  //create matrix with predicted sigma points as columns
  MatrixXd Xsig_pred = MatrixXd(n_x, 2 * n_aug + 1);

  //time diff in secs
  double delta_t = 0.1;

  //predict sigma points
  //avoid division by zero
  //write predicted sigma points into right column
  for(int i = 0; i < Xsig_aug.cols(); ++i) {
//    if (i == 7) {
//      std::cout << "i == " << i << ", x = " << std::endl << Xsig_aug.col(i) << std::endl;
//    }
    Xsig_pred.col(i) = PredictSingleSigmaPoint(Xsig_aug.col(i), delta_t);
  }

  *Xsig_out = Xsig_pred;

// Expected result
//  Xsig_pred =
//   5.93553  6.06251  5.92217   5.9415  5.92361  5.93516  5.93705  5.93553  5.80832  5.94481  5.92935  5.94553  5.93589  5.93401  5.93553
//   1.48939  1.44673  1.66484  1.49719    1.508  1.49001  1.49022  1.48939   1.5308  1.31287  1.48182  1.46967  1.48876  1.48855  1.48939
//    2.2049  2.28414  2.24557  2.29582   2.2049   2.2049  2.23954   2.2049  2.12566  2.16423  2.11398   2.2049   2.2049  2.17026   2.2049
//   0.53678 0.473387 0.678098 0.554557 0.643644 0.543372  0.53678 0.538512 0.600173 0.395462 0.519003 0.429916 0.530188  0.53678 0.535048
//    0.3528 0.299973 0.462123 0.376339  0.48417 0.418721   0.3528 0.387441 0.405627 0.243477 0.329261  0.22143 0.286879   0.3528 0.318159
}

VectorXd UKF::PredictSingleSigmaPoint(const VectorXd & x_aug, double delta_t) {
  double v = x_aug(2);
  double yaw_angle = x_aug(3);
  double yaw_rate = x_aug(4);
  double noise_longitudinal_a = x_aug(5);
  double noise_yaw_a = x_aug(6);

  //do some common calculations
  double sin_yaw_angle = std::sin(yaw_angle);
  double cos_yaw_angle = std::cos(yaw_angle);
  double delta_t_square = delta_t * delta_t;

  double px_change = 0;
  double py_change = 0;

  if (std::fabs(yaw_rate) > 0.001) {
    //calculations specific to this case
    double c1 = v / yaw_rate;
    double c2 = yaw_angle + yaw_rate * delta_t;
    double sin_c2 = std::sin(c2);
    double cos_c2 = std::cos(c2);

    px_change = (c1 * (sin_c2 - sin_yaw_angle));
    py_change = (c1 * (-cos_c2 + cos_yaw_angle));
  }
  else {
    px_change = (v * cos_yaw_angle * delta_t);
    py_change = (v * sin_yaw_angle * delta_t);
  }

  VectorXd x_change = VectorXd(5);
  x_change << px_change,
              py_change,
              0,
              (yaw_rate * delta_t),
              0;

  VectorXd x_noise = VectorXd(5);
  x_noise <<  (0.5 * delta_t_square * cos_yaw_angle * noise_longitudinal_a),
              (0.5 * delta_t_square * sin_yaw_angle * noise_longitudinal_a),
              (delta_t * noise_longitudinal_a),
              (0.5 * delta_t_square * noise_yaw_a),
              (delta_t * noise_yaw_a);

  //add noise to change in x
  x_change += x_noise;

  //extract state vector x from augmented state vector (contains last 2 elements as noise values after augmentation)
  VectorXd x_old = x_aug.head(5);

  //calculate total change in x state
  VectorXd x_prediction = x_old + x_change;

  return x_prediction;
}

<|endoftext|>


<commit_before>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "elfloader/ElfLoader.h"
#include "syscalls/mmap.h"
#include "syscalls/memory.h"
#include "filesystem/FD.h"
#include "MemOp.h"
#include <pthread.h>
#include <vector>

using std::vector;

static pthread_mutex_t lock;
static ElfLoader* executable = NULL;
static ElfLoader* interpreter = NULL;
static vector<string> arguments;
static vector<string> environment;

/* Used when a new process is started; initialises everything that needs to
 * be done anew for any process. (Such as pthread mutexes and GS.)
 */
void InitProcess()
{
	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

	int i = pthread_mutex_init(&lock, &attr);
	if (i)
		error("Failed to init process lock: %d!", i);

	pthread_mutexattr_destroy(&attr);
	InitGSStore();
}

/* Used once we've committed to loading a new executable. Deinits all
 * resources that aren't going to be carried over to the new
 * executable. In particular: memory mappings, file descriptors.
 */
void FlushExecutable()
{
	UnmapAll();
	ClearBrk();
	FD::Flush();
}

void Lock()
{
	pthread_mutex_lock(&lock);
}

void Unlock()
{
	pthread_mutex_unlock(&lock);
}

void Exec(const string& pathname, const char* argv[], const char* environ[])
{
	log("opening %s", argv[0]);

	int argvsize;
	int envsize;

	void* entrypoint;
	ElfLoader* newExecutable = new ElfLoader();
	ElfLoader* newInterpreter = NULL;

	newExecutable->Open(pathname);

	if (newExecutable->HasInterpreter())
	{
		newInterpreter = new ElfLoader();
		newInterpreter->Open(newExecutable->GetInterpreter());
	}

	/* This is the commit point. We're now ready to either load the new
	 * executable, or die trying. As we're about to nuke the process
	 * memory, including the function that called us, we cannot return
	 * from here.
	 */

	try
	{
		/* Before doing anything else, copy the new argument list and
		 * environment into LBW's memory, as we're about to nuke the old
		 * process'.
		 */

		argvsize = 0;
		arguments.clear();
		while (argv[argvsize])
		{
			arguments.push_back(argv[argvsize]);
			argvsize++;
		}

		envsize = 0;
		environment.clear();
		while (environ[envsize])
		{
			environment.push_back(environ[envsize]);
			envsize++;
		}

		/* Now flush the old executable. */

		FlushExecutable();
		if (executable)
		{
			delete executable;
			delete interpreter;
		}
		executable = newExecutable;
		newExecutable = NULL;
		interpreter = newInterpreter;
		newInterpreter = NULL;

		if (interpreter)
		{
			interpreter->Load();
			executable->Load();
			entrypoint = interpreter->GetEntrypoint();
			log("main executable entrypoint %08x", executable->GetEntrypoint());
		}
		else
		{
			executable->Load();
			entrypoint = executable->GetEntrypoint();
		}

		InitProcess();

		int auxsize = 7*2 + 1;

		/* Count the environment and argument array, and copy the data out of
		 * the
		 */

		int arraysize = argvsize + 1 + envsize + 1 + auxsize;
		const char* calldata[arraysize];

		int index = 0;
		for (int i = 0; i < argvsize; i++)
			calldata[index++] = arguments[i].c_str();
		calldata[index++] = NULL;
		for (int i = 0; i < envsize; i++)
			calldata[index++] = environment[i].c_str();
		calldata[index++] = NULL;

		calldata[index++] = (const char*) AT_PHDR;
		calldata[index++] = (const char*) &executable->GetProgramHeader(0);
		calldata[index++] = (const char*) AT_PHENT;
		calldata[index++] = (const char*) executable->GetProgramHeaderSize();
		calldata[index++] = (const char*) AT_PHNUM;
		calldata[index++] = (const char*) executable->GetNumProgramHeaders();
		calldata[index++] = (const char*) AT_ENTRY;
		calldata[index++] = (const char*) executable->GetEntrypoint();
		calldata[index++] = (const char*) AT_PAGESZ;
		calldata[index++] = (const char*) 0x1000;
#if 0
		calldata[index++] = (const char*) AT_BASE;
		calldata[index++] = (const char*) (interpreter ? interpreter->GetLoadAddress() : NULL);
		calldata[index++] = (const char*) AT_FLAGS;
		calldata[index++] = (const char*) 0;
#endif
		calldata[index++] = (const char*) AT_NULL;

		log("executable phdrs at %08x", &executable->GetProgramHeader(0));
		log("running code now");
		//getchar(); asm volatile ("int $3");

		//MemOp::Store(0xf4, 0x7ff62237);
		asm volatile (
			"mov %1, %%esp; " // set stack to startup data
			"push %0; " // argc
			"push %2; " //routine to call
			"xor %%eax, %%eax; "
			"mov %%eax, %%ebx; "
			"mov %%eax, %%ecx; "
			"mov %%eax, %%edx; "
			"mov %%eax, %%esi; "
			"mov %%eax, %%edi; "
			"mov %%eax, %%ebp; "
			"ret"
			:
			: "r" (argvsize),
			  "r" (calldata),
			  "r" (entrypoint)
			);
		_exit(0);
	}
	catch (int e)
	{
		log("failed to exec() process with errno %d", e);
		_exit(1);
	}
	catch (...)
	{
		log("mysterious exception! terminating");
		_exit(1);
	}
}

<commit_msg>Started work on exec()ing Interix native executables.<commit_after>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "elfloader/ElfLoader.h"
#include "syscalls/mmap.h"
#include "syscalls/memory.h"
#include "filesystem/FD.h"
#include "filesystem/VFS.h"
#include "MemOp.h"
#include <pthread.h>
#include <vector>

using std::vector;

static pthread_mutex_t lock;
static ElfLoader* executable = NULL;
static ElfLoader* interpreter = NULL;
static vector<string> arguments;
static vector<string> environment;

enum
{
	UNKNOWN_EXECUTABLE,
	ELF_EXECUTABLE,
	INTERIX_EXECUTABLE
};

/* Used when a new process is started; initialises everything that needs to
 * be done anew for any process. (Such as pthread mutexes and GS.)
 */
void InitProcess()
{
	pthread_mutexattr_t attr;
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

	int i = pthread_mutex_init(&lock, &attr);
	if (i)
		error("Failed to init process lock: %d!", i);

	pthread_mutexattr_destroy(&attr);
	InitGSStore();
}

/* Used once we've committed to loading a new executable. Deinits all
 * resources that aren't going to be carried over to the new
 * executable. In particular: memory mappings, file descriptors.
 */
void FlushExecutable()
{
	UnmapAll();
	ClearBrk();
	FD::Flush();
}

void Lock()
{
	pthread_mutex_lock(&lock);
}

void Unlock()
{
	pthread_mutex_unlock(&lock);
}

static int probe_executable(const string& filename)
{
	Ref<FD> ref = VFS::OpenFile(filename);
	int fd = ref->GetRealFD();

	char buffer[4];
	if (pread(fd, buffer, sizeof(buffer), 0) == -1)
		return UNKNOWN_EXECUTABLE;

	if (memcmp(buffer, "\x7F" "ELF", 4) == 0)
		return ELF_EXECUTABLE;
	if (memcmp(buffer, "MZ", 2) == 0)
		return INTERIX_EXECUTABLE;
	return UNKNOWN_EXECUTABLE;
}

static void elf_exec(const string& pathname, const char* argv[], const char* environ[])
{
	int argvsize;
	int envsize;

	void* entrypoint;
	ElfLoader* newExecutable = new ElfLoader();
	ElfLoader* newInterpreter = NULL;

	newExecutable->Open(pathname);

	if (newExecutable->HasInterpreter())
	{
		newInterpreter = new ElfLoader();
		newInterpreter->Open(newExecutable->GetInterpreter());
	}

	/* This is the commit point. We're now ready to either load the new
	 * executable, or die trying. As we're about to nuke the process
	 * memory, including the function that called us, we cannot return
	 * from here.
	 */

	try
	{
		/* Before doing anything else, copy the new argument list and
		 * environment into LBW's memory, as we're about to nuke the old
		 * process'.
		 */

		argvsize = 0;
		arguments.clear();
		while (argv[argvsize])
		{
			arguments.push_back(argv[argvsize]);
			argvsize++;
		}

		envsize = 0;
		environment.clear();
		while (environ[envsize])
		{
			environment.push_back(environ[envsize]);
			envsize++;
		}

		/* Now flush the old executable. */

		FlushExecutable();
		if (executable)
		{
			delete executable;
			delete interpreter;
		}
		executable = newExecutable;
		newExecutable = NULL;
		interpreter = newInterpreter;
		newInterpreter = NULL;

		if (interpreter)
		{
			interpreter->Load();
			executable->Load();
			entrypoint = interpreter->GetEntrypoint();
			log("main executable entrypoint %08x", executable->GetEntrypoint());
		}
		else
		{
			executable->Load();
			entrypoint = executable->GetEntrypoint();
		}

		InitProcess();

		int auxsize = 7*2 + 1;

		/* Count the environment and argument array, and copy the data out of
		 * the
		 */

		int arraysize = argvsize + 1 + envsize + 1 + auxsize;
		const char* calldata[arraysize];

		int index = 0;
		for (int i = 0; i < argvsize; i++)
			calldata[index++] = arguments[i].c_str();
		calldata[index++] = NULL;
		for (int i = 0; i < envsize; i++)
			calldata[index++] = environment[i].c_str();
		calldata[index++] = NULL;

		calldata[index++] = (const char*) AT_PHDR;
		calldata[index++] = (const char*) &executable->GetProgramHeader(0);
		calldata[index++] = (const char*) AT_PHENT;
		calldata[index++] = (const char*) executable->GetProgramHeaderSize();
		calldata[index++] = (const char*) AT_PHNUM;
		calldata[index++] = (const char*) executable->GetNumProgramHeaders();
		calldata[index++] = (const char*) AT_ENTRY;
		calldata[index++] = (const char*) executable->GetEntrypoint();
		calldata[index++] = (const char*) AT_PAGESZ;
		calldata[index++] = (const char*) 0x1000;
#if 0
		calldata[index++] = (const char*) AT_BASE;
		calldata[index++] = (const char*) (interpreter ? interpreter->GetLoadAddress() : NULL);
		calldata[index++] = (const char*) AT_FLAGS;
		calldata[index++] = (const char*) 0;
#endif
		calldata[index++] = (const char*) AT_NULL;

		log("executable phdrs at %08x", &executable->GetProgramHeader(0));
		log("running code now");
		//getchar(); asm volatile ("int $3");

		//MemOp::Store(0xf4, 0x7ff62237);
		asm volatile (
			"mov %1, %%esp; " // set stack to startup data
			"push %0; " // argc
			"push %2; " //routine to call
			"xor %%eax, %%eax; "
			"mov %%eax, %%ebx; "
			"mov %%eax, %%ecx; "
			"mov %%eax, %%edx; "
			"mov %%eax, %%esi; "
			"mov %%eax, %%edi; "
			"mov %%eax, %%ebp; "
			"ret"
			:
			: "r" (argvsize),
			  "r" (calldata),
			  "r" (entrypoint)
			);
		_exit(0);
	}
	catch (int e)
	{
		log("failed to exec() process with errno %d", e);
		_exit(1);
	}
	catch (...)
	{
		log("mysterious exception! terminating");
		_exit(1);
	}
}

void Exec(const string& pathname, const char* argv[], const char* environ[])
{
	log("opening %s", argv[0]);

	switch (probe_executable(pathname))
	{
		case ELF_EXECUTABLE:
			return elf_exec(pathname, argv, environ);

		case INTERIX_EXECUTABLE:
			error("don't know how to load Interix executables yet");
	}

	throw ENOEXEC;
}
<|endoftext|>