<commit_before>/************************************************************************/
/*                                                                      */
/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_PRINT_BACKTRACE_HXX
#define VIGRA_PRINT_BACKTRACE_HXX

/* Quick-and-dirty way to print a backtrace upon a signal in Linux.

   Especially useful if you can't use a debugger (e.g. on TravisCI).

   Usage:

   Make sure to compile in debug mode.
   Have "addr2line" installed (was already present on TravisCI and our local machines).

   #include <vigra/print_backtrace.hxx>

   int main(int argc, char** argv)
   {
       program_name = argv[0];
       signal(SIGFPE, &vigra_print_stack_trace);  // catch the desired signal

       run_buggy_code();
   }
*/

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

static char * program_name;

static int vigra_addr2line(void const * const addr)
{
    char addr2line_cmd[512] = {0};
    sprintf(addr2line_cmd,"addr2line -C -f -p -i -e %.256s %p", program_name, addr);
    return system(addr2line_cmd);
}

static void vigra_print_stack_trace(int)
{
    int i, trace_size = 0;
    char **messages = (char **)NULL;
    static const int BACKTRACE_SIZE = 100;
    void *stack_traces[BACKTRACE_SIZE];

    trace_size = backtrace(stack_traces, BACKTRACE_SIZE);
    messages = backtrace_symbols(stack_traces, trace_size);

    for (i = 0; i < trace_size; ++i)
    {
        if (vigra_addr2line(stack_traces[i]) != 0)
        {
            printf("  error determining line # for: %sn", messages[i]);
        }
    }
    if (messages) { free(messages); }
    exit(1);
}

#endif // VIGRA_PRINT_BACKTRACE_HXX
<commit_msg>minor improvement of vigra_print_backtrace()<commit_after>/************************************************************************/
/*                                                                      */
/*     Copyright 2013-2014 by Martin Bidlingmaier and Ullrich Koethe    */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_PRINT_BACKTRACE_HXX
#define VIGRA_PRINT_BACKTRACE_HXX

/* Quick-and-dirty way to print a backtrace upon a signal in Linux.

   Especially useful if you can't use a debugger (e.g. on TravisCI).

   Usage:

   Make sure to compile in debug mode.
   Have "addr2line" installed (was already present on TravisCI and our local machines).

   #include <vigra/print_backtrace.hxx>

   int main(int argc, char** argv)
   {
       program_name = argv[0];
       signal(SIGSEGV, &vigra_print_backtrace);  // catch the desired signal

       run_buggy_code();
   }
*/

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

static char * program_name;

static int vigra_addr2line(void const * const addr)
{
    char addr2line_cmd[512] = {0};
    sprintf(addr2line_cmd,"addr2line -C -f -p -i -e %.256s %p", program_name, addr);
    return system(addr2line_cmd);
}

static void vigra_print_backtrace(int sig)
{
    int i, trace_size = 0;
    char **messages = (char **)NULL;
    static const int BACKTRACE_SIZE = 100;
    void *stack_traces[BACKTRACE_SIZE];

    fprintf(stderr, "caught signal %d, printing backtrace\n\n", sig);

    trace_size = backtrace(stack_traces, BACKTRACE_SIZE);
    messages = backtrace_symbols(stack_traces, trace_size);

    for (i = 0; i < trace_size; ++i)
    {
        if (vigra_addr2line(stack_traces[i]) != 0)
        {
            fprintf(stderr, "  error determining line # for: %sn", messages[i]);
        }
    }
    if (messages) { free(messages); }
    exit(1);
}

#endif // VIGRA_PRINT_BACKTRACE_HXX
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bind_node_visitor.cpp
//
// Identification: src/binder/binder_node_visitor.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "binder/bind_node_visitor.h"
#include "catalog/catalog.h"
#include "type/type_id.h"

#include "expression/aggregate_expression.h"
#include "expression/case_expression.h"
#include "expression/function_expression.h"
#include "expression/operator_expression.h"
#include "expression/star_expression.h"
#include "expression/tuple_value_expression.h"

namespace peloton {
namespace binder {

BindNodeVisitor::BindNodeVisitor(concurrency::Transaction *txn,
                                 std::string default_database_name)
    : txn_(txn), default_database_name_(default_database_name) {
  context_ = nullptr;
}

void BindNodeVisitor::BindNameToNode(parser::SQLStatement *tree) {
  tree->Accept(this);
}

void BindNodeVisitor::Visit(parser::SelectStatement *node) {
  // Save the upper level context
  auto pre_context = context_;
  context_ = std::make_shared<BinderContext>();
  context_->upper_context = pre_context;
  if (node->from_table != nullptr) {
    node->from_table->Accept(this);
  }

  if (node->where_clause != nullptr) node->where_clause->Accept(this);
  if (node->order != nullptr) node->order->Accept(this);
  if (node->limit != nullptr) node->limit->Accept(this);
  if (node->group_by != nullptr) node->group_by->Accept(this);
  for (auto &select_element : node->select_list) {
    select_element->Accept(this);
  }

  // Restore the upper level context
  context_ = context_->upper_context;
}

// Some sub query nodes inside SelectStatement
void BindNodeVisitor::Visit(parser::JoinDefinition *node) {
  // The columns in join condition can only bind to the join tables
  node->left->Accept(this);
  node->right->Accept(this);
  node->condition->Accept(this);
}

void BindNodeVisitor::Visit(parser::TableRef *node) {
  // Nested select. Not supported in the current executors
  if (node->select != nullptr) node->select->Accept(this);
  // Join
  else if (node->join != nullptr)
    node->join->Accept(this);
  // Multiple tables
  else if (!node->list.empty()) {
    for (auto &table : node->list) table->Accept(this);
  }
  // Single table
  else {
    context_->AddTable(node, default_database_name_, txn_);
  }
}

void BindNodeVisitor::Visit(parser::GroupByDescription *node) {
  for (auto &col : node->columns) {
    col->Accept(this);
  }
  if (node->having != nullptr) node->having->Accept(this);
}
void BindNodeVisitor::Visit(parser::OrderDescription *node) {
  for (auto &expr : node->exprs)
    if (expr != nullptr) expr->Accept(this);
}

void BindNodeVisitor::Visit(parser::UpdateStatement *node) {
  context_ = std::make_shared<BinderContext>();

  node->table->Accept(this);
  if (node->where != nullptr) node->where->Accept(this);
  for (auto &update : node->updates) {
    update->value->Accept(this);
  }

  // TODO: Update columns are not bound because they are char*
  // not TupleValueExpression in update_statement.h

  context_ = nullptr;
}

void BindNodeVisitor::Visit(parser::DeleteStatement *node) {
  context_ = std::make_shared<BinderContext>();
  node->TryBindDatabaseName(default_database_name_);
  context_->AddTable(node->GetDatabaseName(), node->GetTableName(), txn_);

  if (node->expr != nullptr) node->expr->Accept(this);

  context_ = nullptr;
}

void BindNodeVisitor::Visit(parser::LimitDescription *) {}
void BindNodeVisitor::Visit(parser::CopyStatement *) {}
void BindNodeVisitor::Visit(parser::CreateStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
}
void BindNodeVisitor::Visit(parser::InsertStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
  if (node->select != nullptr) node->select->Accept(this);
  context_ = nullptr;
}
void BindNodeVisitor::Visit(parser::DropStatement *) {}
void BindNodeVisitor::Visit(parser::PrepareStatement *) {}
void BindNodeVisitor::Visit(parser::ExecuteStatement *) {}
void BindNodeVisitor::Visit(parser::TransactionStatement *) {}
void BindNodeVisitor::Visit(parser::AnalyzeStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
}

// void BindNodeVisitor::Visit(const parser::ConstantValueExpression *) {}

void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
  if (!expr->GetIsBound()) {
    std::tuple<oid_t, oid_t, oid_t> col_pos_tuple;
    std::tuple<oid_t, oid_t> table_id_tuple;

    std::string table_name = expr->GetTableName();
    std::string col_name = expr->GetColumnName();

    // Convert all the names to lower cases
    std::transform(table_name.begin(), table_name.end(), table_name.begin(),
                   ::tolower);
    std::transform(col_name.begin(), col_name.end(), col_name.begin(),
                   ::tolower);

    type::TypeId value_type;
    // Table name not specified in the expression
    if (table_name.empty()) {
      if (!BinderContext::GetColumnPosTuple(context_, col_name, col_pos_tuple,
                                            table_name, value_type, txn_))
        throw BinderException("Cannot find column " + col_name);
      expr->SetTableName(table_name);
    }
    // Table name is present
    else {
      // Find the corresponding table in the context
      if (!BinderContext::GetTableIdTuple(context_, table_name,
                                          &table_id_tuple))
        throw BinderException("Invalid table reference " +
                              expr->GetTableName());
      // Find the column offset in that table
      if (!BinderContext::GetColumnPosTuple(col_name, table_id_tuple,
                                            col_pos_tuple, value_type, txn_))
        throw BinderException("Cannot find column " + col_name);
    }
    expr->SetValueType(value_type);
    expr->SetBoundOid(col_pos_tuple);
  }
}

void BindNodeVisitor::Visit(expression::CaseExpression *expr) {
  for (size_t i = 0; i < expr->GetWhenClauseSize(); ++i) {
    expr->GetWhenClauseCond(i)->Accept(this);
  }
}

void BindNodeVisitor::Visit(expression::StarExpression *expr) {
  if (!BinderContext::HasTables(context_))
    throw BinderException("Invalid expression" + expr->GetInfo());
}

// Deduce value type for these expressions
void BindNodeVisitor::Visit(expression::OperatorExpression *expr) {
  SqlNodeVisitor::Visit(expr);
  expr->DeduceExpressionType();
}
void BindNodeVisitor::Visit(expression::AggregateExpression *expr) {
  SqlNodeVisitor::Visit(expr);
  expr->DeduceExpressionType();
}

void BindNodeVisitor::Visit(expression::FunctionExpression *expr) {
  // Visit the subtree first
  SqlNodeVisitor::Visit(expr);

  // Specialize the first argument (DatePartType) for date functions, otherwise
  // we have to do the string comparison to find out the corresponding
  // DatePartType when scanning every tuple.
  auto func_name = expr->GetFuncName();
  if (func_name == "date_trunc" or expr->GetFuncName() == "extract") {
    // Check the type of the first argument. Should be VARCHAR
    auto date_part = expr->GetChild(0);
    if (date_part->GetValueType() != type::TypeId::VARCHAR) {
      throw Exception(EXCEPTION_TYPE_EXPRESSION,
                      "Incorrect argument type to function: " + func_name +
                          ". Argument 0 expected type VARCHAR but found " +
                          TypeIdToString(date_part->GetValueType()) + ".");
    }

    // Convert the first argument to DatePartType
    auto date_part_type = StringToDatePartType(
        date_part->Evaluate(nullptr, nullptr, nullptr).ToString());
    auto date_part_integer = type::ValueFactory::GetIntegerValue(
        static_cast<int32_t>(date_part_type));

    // Replace the first argument with an Integer expression of the DatePartType
    expr->SetChild(0,
                   new expression::ConstantValueExpression(date_part_integer));
  }

  // Check catalog and bind function
  std::vector<type::TypeId> argtypes;
  for (size_t i = 0; i < expr->GetChildrenSize(); i++)
    argtypes.push_back(expr->GetChild(i)->GetValueType());
  // Check and set the function ptr
  auto catalog = catalog::Catalog::GetInstance();
  const catalog::FunctionData &func_data =
      catalog->GetFunction(expr->GetFuncName(), argtypes);
  LOG_DEBUG("Function %s found in the catalog", func_data.func_name_.c_str());
  LOG_DEBUG("Argument num: %ld", func_data.argument_types_.size());
  expr->SetFunctionExpressionParameters(func_data.func_, func_data.return_type_,
                                        func_data.argument_types_);
}

}  // namespace binder
}  // namespace peloton
<commit_msg>Small fix for code consistency.<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bind_node_visitor.cpp
//
// Identification: src/binder/binder_node_visitor.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "binder/bind_node_visitor.h"
#include "catalog/catalog.h"
#include "type/type_id.h"

#include "expression/aggregate_expression.h"
#include "expression/case_expression.h"
#include "expression/function_expression.h"
#include "expression/operator_expression.h"
#include "expression/star_expression.h"
#include "expression/tuple_value_expression.h"

namespace peloton {
namespace binder {

BindNodeVisitor::BindNodeVisitor(concurrency::Transaction *txn,
                                 std::string default_database_name)
    : txn_(txn), default_database_name_(default_database_name) {
  context_ = nullptr;
}

void BindNodeVisitor::BindNameToNode(parser::SQLStatement *tree) {
  tree->Accept(this);
}

void BindNodeVisitor::Visit(parser::SelectStatement *node) {
  // Save the upper level context
  auto pre_context = context_;
  context_ = std::make_shared<BinderContext>();
  context_->upper_context = pre_context;
  if (node->from_table != nullptr) {
    node->from_table->Accept(this);
  }

  if (node->where_clause != nullptr) node->where_clause->Accept(this);
  if (node->order != nullptr) node->order->Accept(this);
  if (node->limit != nullptr) node->limit->Accept(this);
  if (node->group_by != nullptr) node->group_by->Accept(this);
  for (auto &select_element : node->select_list) {
    select_element->Accept(this);
  }

  // Restore the upper level context
  context_ = context_->upper_context;
}

// Some sub query nodes inside SelectStatement
void BindNodeVisitor::Visit(parser::JoinDefinition *node) {
  // The columns in join condition can only bind to the join tables
  node->left->Accept(this);
  node->right->Accept(this);
  node->condition->Accept(this);
}

void BindNodeVisitor::Visit(parser::TableRef *node) {
  // Nested select. Not supported in the current executors
  if (node->select != nullptr) node->select->Accept(this);
  // Join
  else if (node->join != nullptr)
    node->join->Accept(this);
  // Multiple tables
  else if (!node->list.empty()) {
    for (auto &table : node->list) table->Accept(this);
  }
  // Single table
  else {
    context_->AddTable(node, default_database_name_, txn_);
  }
}

void BindNodeVisitor::Visit(parser::GroupByDescription *node) {
  for (auto &col : node->columns) {
    col->Accept(this);
  }
  if (node->having != nullptr) node->having->Accept(this);
}
void BindNodeVisitor::Visit(parser::OrderDescription *node) {
  for (auto &expr : node->exprs)
    if (expr != nullptr) expr->Accept(this);
}

void BindNodeVisitor::Visit(parser::UpdateStatement *node) {
  context_ = std::make_shared<BinderContext>();

  node->table->Accept(this);
  if (node->where != nullptr) node->where->Accept(this);
  for (auto &update : node->updates) {
    update->value->Accept(this);
  }

  // TODO: Update columns are not bound because they are char*
  // not TupleValueExpression in update_statement.h

  context_ = nullptr;
}

void BindNodeVisitor::Visit(parser::DeleteStatement *node) {
  context_ = std::make_shared<BinderContext>();
  node->TryBindDatabaseName(default_database_name_);
  context_->AddTable(node->GetDatabaseName(), node->GetTableName(), txn_);

  if (node->expr != nullptr) node->expr->Accept(this);

  context_ = nullptr;
}

void BindNodeVisitor::Visit(parser::LimitDescription *) {}
void BindNodeVisitor::Visit(parser::CopyStatement *) {}
void BindNodeVisitor::Visit(parser::CreateStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
}
void BindNodeVisitor::Visit(parser::InsertStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
  if (node->select != nullptr) node->select->Accept(this);
  context_ = nullptr;
}
void BindNodeVisitor::Visit(parser::DropStatement *) {}
void BindNodeVisitor::Visit(parser::PrepareStatement *) {}
void BindNodeVisitor::Visit(parser::ExecuteStatement *) {}
void BindNodeVisitor::Visit(parser::TransactionStatement *) {}
void BindNodeVisitor::Visit(parser::AnalyzeStatement *node) {
  node->TryBindDatabaseName(default_database_name_);
}

// void BindNodeVisitor::Visit(const parser::ConstantValueExpression *) {}

void BindNodeVisitor::Visit(expression::TupleValueExpression *expr) {
  if (!expr->GetIsBound()) {
    std::tuple<oid_t, oid_t, oid_t> col_pos_tuple;
    std::tuple<oid_t, oid_t> table_id_tuple;

    std::string table_name = expr->GetTableName();
    std::string col_name = expr->GetColumnName();

    // Convert all the names to lower cases
    std::transform(table_name.begin(), table_name.end(), table_name.begin(),
                   ::tolower);
    std::transform(col_name.begin(), col_name.end(), col_name.begin(),
                   ::tolower);

    type::TypeId value_type;
    // Table name not specified in the expression
    if (table_name.empty()) {
      if (!BinderContext::GetColumnPosTuple(context_, col_name, col_pos_tuple,
                                            table_name, value_type, txn_))
        throw BinderException("Cannot find column " + col_name);
      expr->SetTableName(table_name);
    }
    // Table name is present
    else {
      // Find the corresponding table in the context
      if (!BinderContext::GetTableIdTuple(context_, table_name,
                                          &table_id_tuple))
        throw BinderException("Invalid table reference " +
                              expr->GetTableName());
      // Find the column offset in that table
      if (!BinderContext::GetColumnPosTuple(col_name, table_id_tuple,
                                            col_pos_tuple, value_type, txn_))
        throw BinderException("Cannot find column " + col_name);
    }
    expr->SetValueType(value_type);
    expr->SetBoundOid(col_pos_tuple);
  }
}

void BindNodeVisitor::Visit(expression::CaseExpression *expr) {
  for (size_t i = 0; i < expr->GetWhenClauseSize(); ++i) {
    expr->GetWhenClauseCond(i)->Accept(this);
  }
}

void BindNodeVisitor::Visit(expression::StarExpression *expr) {
  if (!BinderContext::HasTables(context_))
    throw BinderException("Invalid expression" + expr->GetInfo());
}

// Deduce value type for these expressions
void BindNodeVisitor::Visit(expression::OperatorExpression *expr) {
  SqlNodeVisitor::Visit(expr);
  expr->DeduceExpressionType();
}
void BindNodeVisitor::Visit(expression::AggregateExpression *expr) {
  SqlNodeVisitor::Visit(expr);
  expr->DeduceExpressionType();
}

void BindNodeVisitor::Visit(expression::FunctionExpression *expr) {
  // Visit the subtree first
  SqlNodeVisitor::Visit(expr);

  // Specialize the first argument (DatePartType) for date functions, otherwise
  // we have to do the string comparison to find out the corresponding
  // DatePartType when scanning every tuple.
  auto func_name = expr->GetFuncName();
  if (func_name == "date_trunc" or func_name == "extract") {
    // Check the type of the first argument. Should be VARCHAR
    auto date_part = expr->GetChild(0);
    if (date_part->GetValueType() != type::TypeId::VARCHAR) {
      throw Exception(EXCEPTION_TYPE_EXPRESSION,
                      "Incorrect argument type to function: " + func_name +
                          ". Argument 0 expected type VARCHAR but found " +
                          TypeIdToString(date_part->GetValueType()) + ".");
    }

    // Convert the first argument to DatePartType
    auto date_part_type = StringToDatePartType(
        date_part->Evaluate(nullptr, nullptr, nullptr).ToString());
    auto date_part_integer = type::ValueFactory::GetIntegerValue(
        static_cast<int32_t>(date_part_type));

    // Replace the first argument with an Integer expression of the DatePartType
    expr->SetChild(0,
                   new expression::ConstantValueExpression(date_part_integer));
  }

  // Check catalog and bind function
  std::vector<type::TypeId> argtypes;
  for (size_t i = 0; i < expr->GetChildrenSize(); i++)
    argtypes.push_back(expr->GetChild(i)->GetValueType());
  // Check and set the function ptr
  auto catalog = catalog::Catalog::GetInstance();
  const catalog::FunctionData &func_data =
      catalog->GetFunction(expr->GetFuncName(), argtypes);
  LOG_DEBUG("Function %s found in the catalog", func_data.func_name_.c_str());
  LOG_DEBUG("Argument num: %ld", func_data.argument_types_.size());
  expr->SetFunctionExpressionParameters(func_data.func_, func_data.return_type_,
                                        func_data.argument_types_);
}

}  // namespace binder
}  // namespace peloton
<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <iostream>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>

#include <boost/mpl/set.hpp>
#include <boost/optional.hpp>

#include "blackhole/attribute/set.hpp"
#include "blackhole/config.hpp"
#include "blackhole/detail/array.hpp"
#include "blackhole/detail/iterator/join.hpp"
#include "blackhole/detail/traits/tuple.hpp"
#include "blackhole/detail/traits/unique.hpp"

namespace blackhole {

namespace attribute {

template<class T>
struct extractor;

template<class... Args>
struct tuple_empty;

namespace compare_by {

struct name_t {
    const std::string name;

    bool operator()(const set_t::value_type& v) const {
        return v.first == name;
    }
};

} // namespace

class set_view_t {
    template<class T> friend struct extractor;
    template<class... Args> friend struct tuple_empty;

public:
    typedef aux::iterator::join_t<set_t, true> const_iterator;

    struct internal_set_t { set_t v; };
    struct external_set_t { set_t v; };

private:
    internal_set_t internal;  // Severity, message, timestamp. Maybe pid, tid.
    external_set_t external;  // All other.

public:
    set_view_t() = default;

    set_view_t(set_t external, set_t&& internal) :
        internal({ std::move(internal) }),
        external({ std::move(external) })
    {}

    bool
    empty() const BLACKHOLE_NOEXCEPT {
        return internal.v.empty() && external.v.empty();
    }

    //! Message is the only(?) late attribute allowed to set internally.
    void message(const std::string& message) {
        internal.v.emplace_back("message", message);
    }

    void message(std::string&& message) {
        internal.v.emplace_back("message", std::move(message));
    }

    //! Intentionally allow to insert only into external attribute set.
    void insert(pair_t pair) {
        external.v.emplace_back(std::move(pair));
    }

    //! Intentionally allow to insert only into external attribute set.
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last) {
        std::copy(first, last, std::back_inserter(external.v));
    }

    const_iterator begin() const BLACKHOLE_NOEXCEPT {
        return const_iterator(aux::make_array(&internal.v, &external.v));
    }

    const_iterator end() const BLACKHOLE_NOEXCEPT {
        return const_iterator::invalid(aux::make_array(&internal.v, &external.v));
    }

    boost::optional<const attribute_t&>
    find(const std::string& name) const BLACKHOLE_NOEXCEPT {
        const compare_by::name_t action { name };

        auto it = std::find_if(internal.v.begin(), internal.v.end(), action);
        if (it != internal.v.end()) {
            return it->second;
        }

        it = std::find_if(external.v.begin(), external.v.end(), action);
        if (it != external.v.end()) {
            return it->second;
        }

        return boost::none;
    }

    const attribute_t& at(const std::string& name) const {
        auto value = find(name);
        if (!value) {
            throw std::out_of_range(name);
        }

        return *value;
    }
};

template<>
struct tuple_empty<> {
    static inline bool empty(const set_view_t&) {
        return true;
    }
};

template<>
struct tuple_empty<set_view_t::internal_set_t> {
    static inline bool empty(const set_view_t& view) {
        return view.internal.v.empty();
    }
};

template<>
struct tuple_empty<set_view_t::external_set_t> {
    static inline bool empty(const set_view_t& view) {
        return view.external.v.empty();
    }
};

template<class T, class... Args>
struct tuple_empty<T, Args...> {
    static inline bool empty(const set_view_t& view) {
        return tuple_empty<T>::empty(view) &&
                tuple_empty<Args...>::empty(view);
    }
};

template<>
struct extractor<set_view_t::internal_set_t> {
    static
    inline
    const set_t*
    extract(const set_view_t& view) {
        return &view.internal.v;
    }
};

template<>
struct extractor<set_view_t::external_set_t> {
    static
    inline
    const set_t*
    extract(const set_view_t& view) {
        return &view.external.v;
    }
};

template<class... T>
class partial_view_t {
    static_assert(unique<T...>::value, "all attribute set types must be unique");

    typedef std::array<const set_t*, sizeof...(T)> array_type;

public:
    typedef set_view_t::const_iterator const_iterator;

private:
    const set_view_t& view;

public:
    partial_view_t(const set_view_t& view) :
        view(view)
    {}

    bool
    empty() const BLACKHOLE_NOEXCEPT {
        return tuple_empty<T...>::empty(view);
    }

    const_iterator
    begin() const BLACKHOLE_NOEXCEPT {
        return const_iterator(
            array_type {{ extractor<T>::extract(view)... }}
        );
    }

    const_iterator
    end() const BLACKHOLE_NOEXCEPT {
        return const_iterator::invalid(
            array_type {{ extractor<T>::extract(view)... }}
        );
    }
};

} // namespace attribute

} // namespace blackhole
<commit_msg>[Detail] Avoid unnecessary copying.<commit_after>#pragma once

#include <array>
#include <iostream>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>

#include <boost/mpl/set.hpp>
#include <boost/optional.hpp>

#include "blackhole/attribute/set.hpp"
#include "blackhole/config.hpp"
#include "blackhole/detail/array.hpp"
#include "blackhole/detail/iterator/join.hpp"
#include "blackhole/detail/traits/tuple.hpp"
#include "blackhole/detail/traits/unique.hpp"

namespace blackhole {

namespace attribute {

template<class T>
struct extractor;

template<class... Args>
struct tuple_empty;

namespace compare_by {

struct name_t {
    const std::string& name;

    bool operator()(const set_t::value_type& v) const {
        return v.first == name;
    }
};

} // namespace

class set_view_t {
    template<class T> friend struct extractor;
    template<class... Args> friend struct tuple_empty;

public:
    typedef aux::iterator::join_t<set_t, true> const_iterator;

    struct internal_set_t { set_t v; };
    struct external_set_t { set_t v; };

private:
    internal_set_t internal;  // Severity, message, timestamp. Maybe pid, tid.
    external_set_t external;  // All other.

public:
    set_view_t() = default;

    set_view_t(set_t external, set_t&& internal) :
        internal({ std::move(internal) }),
        external({ std::move(external) })
    {}

    bool
    empty() const BLACKHOLE_NOEXCEPT {
        return internal.v.empty() && external.v.empty();
    }

    //! Message is the only(?) late attribute allowed to set internally.
    void message(const std::string& message) {
        internal.v.emplace_back("message", message);
    }

    void message(std::string&& message) {
        internal.v.emplace_back("message", std::move(message));
    }

    //! Intentionally allow to insert only into external attribute set.
    void insert(pair_t pair) {
        external.v.emplace_back(std::move(pair));
    }

    //! Intentionally allow to insert only into external attribute set.
    template<typename InputIterator>
    void insert(InputIterator first, InputIterator last) {
        std::copy(first, last, std::back_inserter(external.v));
    }

    const_iterator begin() const BLACKHOLE_NOEXCEPT {
        return const_iterator(aux::make_array(&internal.v, &external.v));
    }

    const_iterator end() const BLACKHOLE_NOEXCEPT {
        return const_iterator::invalid(aux::make_array(&internal.v, &external.v));
    }

    boost::optional<const attribute_t&>
    find(const std::string& name) const BLACKHOLE_NOEXCEPT {
        const compare_by::name_t action { name };

        auto it = std::find_if(internal.v.begin(), internal.v.end(), action);
        if (it != internal.v.end()) {
            return it->second;
        }

        it = std::find_if(external.v.begin(), external.v.end(), action);
        if (it != external.v.end()) {
            return it->second;
        }

        return boost::none;
    }

    const attribute_t& at(const std::string& name) const {
        auto value = find(name);
        if (!value) {
            throw std::out_of_range(name);
        }

        return *value;
    }
};

template<>
struct tuple_empty<> {
    static inline bool empty(const set_view_t&) {
        return true;
    }
};

template<>
struct tuple_empty<set_view_t::internal_set_t> {
    static inline bool empty(const set_view_t& view) {
        return view.internal.v.empty();
    }
};

template<>
struct tuple_empty<set_view_t::external_set_t> {
    static inline bool empty(const set_view_t& view) {
        return view.external.v.empty();
    }
};

template<class T, class... Args>
struct tuple_empty<T, Args...> {
    static inline bool empty(const set_view_t& view) {
        return tuple_empty<T>::empty(view) &&
                tuple_empty<Args...>::empty(view);
    }
};

template<>
struct extractor<set_view_t::internal_set_t> {
    static
    inline
    const set_t*
    extract(const set_view_t& view) {
        return &view.internal.v;
    }
};

template<>
struct extractor<set_view_t::external_set_t> {
    static
    inline
    const set_t*
    extract(const set_view_t& view) {
        return &view.external.v;
    }
};

template<class... T>
class partial_view_t {
    static_assert(unique<T...>::value, "all attribute set types must be unique");

    typedef std::array<const set_t*, sizeof...(T)> array_type;

public:
    typedef set_view_t::const_iterator const_iterator;

private:
    const set_view_t& view;

public:
    partial_view_t(const set_view_t& view) :
        view(view)
    {}

    bool
    empty() const BLACKHOLE_NOEXCEPT {
        return tuple_empty<T...>::empty(view);
    }

    const_iterator
    begin() const BLACKHOLE_NOEXCEPT {
        return const_iterator(
            array_type {{ extractor<T>::extract(view)... }}
        );
    }

    const_iterator
    end() const BLACKHOLE_NOEXCEPT {
        return const_iterator::invalid(
            array_type {{ extractor<T>::extract(view)... }}
        );
    }
};

} // namespace attribute

} // namespace blackhole
<|endoftext|>


<commit_before>// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/dartdev_isolate.h"

#if !defined(DART_PRECOMPILED_RUNTIME)

#include <functional>
#include <memory>

#include "bin/directory.h"
#include "bin/error_exit.h"
#include "bin/exe_utils.h"
#include "bin/file.h"
#include "bin/lockers.h"
#include "bin/platform.h"
#include "bin/process.h"
#include "include/dart_embedder_api.h"
#include "platform/utils.h"

#define CHECK_RESULT(result)                                                   \
  if (Dart_IsError(result)) {                                                  \
    ProcessError(Dart_GetError(result), kErrorExitCode);                       \
    if (send_port_id != ILLEGAL_PORT) {                                        \
      Dart_CloseNativePort(send_port_id);                                      \
    }                                                                          \
    Dart_ExitScope();                                                          \
    Dart_ExitIsolate();                                                        \
    return;                                                                    \
  }

namespace dart {
namespace bin {

DartDevIsolate::DartDevRunner DartDevIsolate::runner_ =
    DartDevIsolate::DartDevRunner();
bool DartDevIsolate::should_run_dart_dev_ = false;
Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
    DartDevIsolate::DartDev_Result_Unknown;
char** DartDevIsolate::DartDevRunner::script_ = nullptr;
std::unique_ptr<char*[], void (*)(char*[])>
    DartDevIsolate::DartDevRunner::argv_ =
        std::unique_ptr<char*[], void (*)(char**)>(nullptr, [](char**) {});
intptr_t DartDevIsolate::DartDevRunner::argc_ = 0;

bool DartDevIsolate::ShouldParseCommand(const char* script_uri) {
  // If script_uri is not a file path or of a known URI scheme, we can assume
  // that this is a DartDev command.
  return (!File::ExistsUri(nullptr, script_uri) &&
          (strncmp(script_uri, "http://", 7) != 0) &&
          (strncmp(script_uri, "https://", 8) != 0) &&
          (strncmp(script_uri, "file://", 7) != 0) &&
          (strncmp(script_uri, "package:", 8) != 0) &&
          (strncmp(script_uri, "google3://", 10) != 0));
}

const char* DartDevIsolate::TryResolveDartDevSnapshotPath() {
  // |dir_prefix| includes the last path seperator.
  auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();

  // First assume we're in dart-sdk/bin.
  char* snapshot_path =
      Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get());
  if (File::Exists(nullptr, snapshot_path)) {
    return snapshot_path;
  }
  free(snapshot_path);

  // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
  // directories. Try to use a snapshot rom a previously built SDK.
  snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get());
  if (File::Exists(nullptr, snapshot_path)) {
    return snapshot_path;
  }
  free(snapshot_path);

  Syslog::PrintErr("Could not find DartDev snapshot.\n");
  return nullptr;
}

void DartDevIsolate::DartDevRunner::Run(
    Dart_IsolateGroupCreateCallback create_isolate,
    const char* packages_file,
    char** script,
    CommandLineOptions* dart_options) {
  create_isolate_ = create_isolate;
  dart_options_ = dart_options;
  packages_file_ = packages_file;
  script_ = script;

  MonitorLocker locker(monitor_);
  int result = Thread::Start("DartDev Runner", RunCallback,
                             reinterpret_cast<uword>(this));
  if (result != 0) {
    FATAL1("Failed to start DartDev thread: %d", result);
  }
  monitor_->WaitMicros(Monitor::kNoTimeout);

  if (result_ == DartDevIsolate::DartDev_Result_Run) {
    // Clear the DartDev dart_options and replace them with the processed
    // options provided by DartDev.
    dart_options_->Reset();
    for (intptr_t i = 0; i < argc_; ++i) {
      dart_options_->AddArguments(const_cast<const char**>(argv_.get()), argc_);
    }
  }
}

static Dart_CObject* GetArrayItem(Dart_CObject* message, intptr_t index) {
  return message->value.as_array.values[index];
}

void DartDevIsolate::DartDevRunner::DartDevResultCallback(
    Dart_Port dest_port_id,
    Dart_CObject* message) {
  ASSERT(message->type == Dart_CObject_kArray);
  int32_t type = GetArrayItem(message, 0)->value.as_int32;
  switch (type) {
    case DartDevIsolate::DartDev_Result_Run: {
      result_ = DartDevIsolate::DartDev_Result_Run;
      ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
      if (*script_ != nullptr) {
        free(*script_);
      }
      *script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
      ASSERT(GetArrayItem(message, 2)->type == Dart_CObject_kArray);
      Dart_CObject* args = GetArrayItem(message, 2);
      argc_ = args->value.as_array.length;
      Dart_CObject** dart_args = args->value.as_array.values;

      auto deleter = [](char** args) {
        for (intptr_t i = 0; i < argc_; ++i) {
          free(args[i]);
        }
        delete[] args;
      };

      argv_ =
          std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_], deleter);
      for (intptr_t i = 0; i < argc_; ++i) {
        argv_[i] = Utils::StrDup(dart_args[i]->value.as_string);
      }
      break;
    }
    case DartDevIsolate::DartDev_Result_Exit: {
      ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
      int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;

      // If we're given a non-zero exit code, DartDev is signaling for us to
      // shutdown.
      if (dartdev_exit_code != 0) {
        Process::SetGlobalExitCode(dartdev_exit_code);
      }

      // If DartDev hasn't signaled for us to do anything else, we can assume
      // there's nothing else for the VM to run and that we can exit.
      if (result_ == DartDevIsolate::DartDev_Result_Unknown) {
        result_ = DartDevIsolate::DartDev_Result_Exit;
      }

      // DartDev is done processing the command. Unblock the main thread and
      // continue the launch procedure.
      DartDevRunner::monitor_->Notify();
      break;
    }
    default:
      UNREACHABLE();
  }
}

void DartDevIsolate::DartDevRunner::RunCallback(uword args) {
  MonitorLocker locker_(DartDevRunner::monitor_);
  DartDevRunner* runner = reinterpret_cast<DartDevRunner*>(args);
  const char* dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
  if (dartdev_path == nullptr) {
    ProcessError("Failed to find DartDev snapshot.", kErrorExitCode);
    return;
  }
  Dart_IsolateFlags flags;
  Dart_IsolateFlagsInitialize(&flags);
  char* error;
  Dart_Isolate dartdev_isolate = runner->create_isolate_(
      dartdev_path, "dartdev", nullptr, runner->packages_file_, &flags,
      NULL /* callback_data */, const_cast<char**>(&error));
  free(const_cast<char*>(dartdev_path));

  if (dartdev_isolate == nullptr) {
    ProcessError(error, kErrorExitCode);
    return;
  }

  Dart_EnterIsolate(dartdev_isolate);
  Dart_EnterScope();

  // Retrieve the DartDev entrypoint.
  Dart_Port send_port_id = ILLEGAL_PORT;
  Dart_Handle root_lib = Dart_RootLibrary();
  Dart_Handle main_closure =
      Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
  CHECK_RESULT(main_closure);

  if (!Dart_IsClosure(main_closure)) {
    ProcessError("Unable to find 'main' in root library 'dartdev'",
                 kErrorExitCode);
    Dart_ExitScope();
    Dart_ExitIsolate();
    return;
  }

  // Create a SendPort that DartDev can use to communicate its results over.
  send_port_id = Dart_NewNativePort("dartdev", DartDevResultCallback, false);
  ASSERT(send_port_id != ILLEGAL_PORT);
  Dart_Handle send_port = Dart_NewSendPort(send_port_id);
  CHECK_RESULT(send_port);

  const intptr_t kNumIsolateArgs = 7;
  Dart_Handle isolate_args[kNumIsolateArgs];
  isolate_args[0] = Dart_Null();   // parentPort
  isolate_args[1] = main_closure;  // entryPoint
  isolate_args[2] = runner->dart_options_->CreateRuntimeOptions();  // args
  isolate_args[3] = send_port;                                      // message
  isolate_args[4] = Dart_True();  // isSpawnUri
  isolate_args[5] = Dart_Null();  // controlPort
  isolate_args[6] = Dart_Null();  // capabilities

  Dart_Handle isolate_lib =
      Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
  Dart_Handle result =
      Dart_Invoke(isolate_lib, Dart_NewStringFromCString("_startIsolate"),
                  kNumIsolateArgs, isolate_args);
  CHECK_RESULT(result);
  CHECK_RESULT(Dart_RunLoop());

  Dart_CloseNativePort(send_port_id);

  Dart_ExitScope();
  Dart_ShutdownIsolate();
}

void DartDevIsolate::DartDevRunner::ProcessError(const char* msg,
                                                 int32_t exit_code) {
  Syslog::PrintErr("%s\n", msg);
  Process::SetGlobalExitCode(exit_code);
  result_ = DartDevIsolate::DartDev_Result_Exit;
  DartDevRunner::monitor_->Notify();
}

DartDevIsolate::DartDev_Result DartDevIsolate::RunDartDev(
    Dart_IsolateGroupCreateCallback create_isolate,
    const char* packages_file,
    char** script,
    CommandLineOptions* dart_options) {
  runner_.Run(create_isolate, packages_file, script, dart_options);
  return runner_.result();
}

#endif  // if !defined(DART_PRECOMPILED_RUNTIME)

}  // namespace bin
}  // namespace dart
<commit_msg>[ VM / DartDev ] Spawn DartDev isolate with flags matching those used to generate the snapshot<commit_after>// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/dartdev_isolate.h"

#if !defined(DART_PRECOMPILED_RUNTIME)

#include <functional>
#include <memory>

#include "bin/directory.h"
#include "bin/error_exit.h"
#include "bin/exe_utils.h"
#include "bin/file.h"
#include "bin/lockers.h"
#include "bin/platform.h"
#include "bin/process.h"
#include "include/dart_embedder_api.h"
#include "platform/utils.h"

#define CHECK_RESULT(result)                                                   \
  if (Dart_IsError(result)) {                                                  \
    ProcessError(Dart_GetError(result), kErrorExitCode);                       \
    if (send_port_id != ILLEGAL_PORT) {                                        \
      Dart_CloseNativePort(send_port_id);                                      \
    }                                                                          \
    Dart_ExitScope();                                                          \
    Dart_ExitIsolate();                                                        \
    return;                                                                    \
  }

namespace dart {
namespace bin {

DartDevIsolate::DartDevRunner DartDevIsolate::runner_ =
    DartDevIsolate::DartDevRunner();
bool DartDevIsolate::should_run_dart_dev_ = false;
Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
    DartDevIsolate::DartDev_Result_Unknown;
char** DartDevIsolate::DartDevRunner::script_ = nullptr;
std::unique_ptr<char*[], void (*)(char*[])>
    DartDevIsolate::DartDevRunner::argv_ =
        std::unique_ptr<char*[], void (*)(char**)>(nullptr, [](char**) {});
intptr_t DartDevIsolate::DartDevRunner::argc_ = 0;

bool DartDevIsolate::ShouldParseCommand(const char* script_uri) {
  // If script_uri is not a file path or of a known URI scheme, we can assume
  // that this is a DartDev command.
  return (!File::ExistsUri(nullptr, script_uri) &&
          (strncmp(script_uri, "http://", 7) != 0) &&
          (strncmp(script_uri, "https://", 8) != 0) &&
          (strncmp(script_uri, "file://", 7) != 0) &&
          (strncmp(script_uri, "package:", 8) != 0) &&
          (strncmp(script_uri, "google3://", 10) != 0));
}

const char* DartDevIsolate::TryResolveDartDevSnapshotPath() {
  // |dir_prefix| includes the last path seperator.
  auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();

  // First assume we're in dart-sdk/bin.
  char* snapshot_path =
      Utils::SCreate("%ssnapshots/dartdev.dart.snapshot", dir_prefix.get());
  if (File::Exists(nullptr, snapshot_path)) {
    return snapshot_path;
  }
  free(snapshot_path);

  // If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
  // directories. Try to use a snapshot rom a previously built SDK.
  snapshot_path = Utils::SCreate("%sdartdev.dart.snapshot", dir_prefix.get());
  if (File::Exists(nullptr, snapshot_path)) {
    return snapshot_path;
  }
  free(snapshot_path);

  Syslog::PrintErr("Could not find DartDev snapshot.\n");
  return nullptr;
}

void DartDevIsolate::DartDevRunner::Run(
    Dart_IsolateGroupCreateCallback create_isolate,
    const char* packages_file,
    char** script,
    CommandLineOptions* dart_options) {
  create_isolate_ = create_isolate;
  dart_options_ = dart_options;
  packages_file_ = packages_file;
  script_ = script;

  MonitorLocker locker(monitor_);
  int result = Thread::Start("DartDev Runner", RunCallback,
                             reinterpret_cast<uword>(this));
  if (result != 0) {
    FATAL1("Failed to start DartDev thread: %d", result);
  }
  monitor_->WaitMicros(Monitor::kNoTimeout);

  if (result_ == DartDevIsolate::DartDev_Result_Run) {
    // Clear the DartDev dart_options and replace them with the processed
    // options provided by DartDev.
    dart_options_->Reset();
    for (intptr_t i = 0; i < argc_; ++i) {
      dart_options_->AddArguments(const_cast<const char**>(argv_.get()), argc_);
    }
  }
}

static Dart_CObject* GetArrayItem(Dart_CObject* message, intptr_t index) {
  return message->value.as_array.values[index];
}

void DartDevIsolate::DartDevRunner::DartDevResultCallback(
    Dart_Port dest_port_id,
    Dart_CObject* message) {
  ASSERT(message->type == Dart_CObject_kArray);
  int32_t type = GetArrayItem(message, 0)->value.as_int32;
  switch (type) {
    case DartDevIsolate::DartDev_Result_Run: {
      result_ = DartDevIsolate::DartDev_Result_Run;
      ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
      if (*script_ != nullptr) {
        free(*script_);
      }
      *script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
      ASSERT(GetArrayItem(message, 2)->type == Dart_CObject_kArray);
      Dart_CObject* args = GetArrayItem(message, 2);
      argc_ = args->value.as_array.length;
      Dart_CObject** dart_args = args->value.as_array.values;

      auto deleter = [](char** args) {
        for (intptr_t i = 0; i < argc_; ++i) {
          free(args[i]);
        }
        delete[] args;
      };

      argv_ =
          std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_], deleter);
      for (intptr_t i = 0; i < argc_; ++i) {
        argv_[i] = Utils::StrDup(dart_args[i]->value.as_string);
      }
      break;
    }
    case DartDevIsolate::DartDev_Result_Exit: {
      ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
      int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;

      // If we're given a non-zero exit code, DartDev is signaling for us to
      // shutdown.
      if (dartdev_exit_code != 0) {
        Process::SetGlobalExitCode(dartdev_exit_code);
      }

      // If DartDev hasn't signaled for us to do anything else, we can assume
      // there's nothing else for the VM to run and that we can exit.
      if (result_ == DartDevIsolate::DartDev_Result_Unknown) {
        result_ = DartDevIsolate::DartDev_Result_Exit;
      }

      // DartDev is done processing the command. Unblock the main thread and
      // continue the launch procedure.
      DartDevRunner::monitor_->Notify();
      break;
    }
    default:
      UNREACHABLE();
  }
}

void DartDevIsolate::DartDevRunner::RunCallback(uword args) {
  MonitorLocker locker_(DartDevRunner::monitor_);
  DartDevRunner* runner = reinterpret_cast<DartDevRunner*>(args);

  // TODO(bkonyi): bring up DartDev from kernel instead of a app-jit snapshot.
  // See https://github.com/dart-lang/sdk/issues/42804
  const char* dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
  if (dartdev_path == nullptr) {
    ProcessError("Failed to find DartDev snapshot.", kErrorExitCode);
    return;
  }

  // Hardcode flags to match those used to generate the DartDev snapshot.
  Dart_IsolateFlags flags;
  Dart_IsolateFlagsInitialize(&flags);
  flags.enable_asserts = false;
  flags.null_safety = false;
  flags.use_field_guards = true;
  flags.use_osr = true;

  char* error;
  Dart_Isolate dartdev_isolate = runner->create_isolate_(
      dartdev_path, "dartdev", nullptr, runner->packages_file_, &flags,
      NULL /* callback_data */, const_cast<char**>(&error));
  free(const_cast<char*>(dartdev_path));

  if (dartdev_isolate == nullptr) {
    ProcessError(error, kErrorExitCode);
    return;
  }

  Dart_EnterIsolate(dartdev_isolate);
  Dart_EnterScope();

  // Retrieve the DartDev entrypoint.
  Dart_Port send_port_id = ILLEGAL_PORT;
  Dart_Handle root_lib = Dart_RootLibrary();
  Dart_Handle main_closure =
      Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
  CHECK_RESULT(main_closure);

  if (!Dart_IsClosure(main_closure)) {
    ProcessError("Unable to find 'main' in root library 'dartdev'",
                 kErrorExitCode);
    Dart_ExitScope();
    Dart_ExitIsolate();
    return;
  }

  // Create a SendPort that DartDev can use to communicate its results over.
  send_port_id = Dart_NewNativePort("dartdev", DartDevResultCallback, false);
  ASSERT(send_port_id != ILLEGAL_PORT);
  Dart_Handle send_port = Dart_NewSendPort(send_port_id);
  CHECK_RESULT(send_port);

  const intptr_t kNumIsolateArgs = 7;
  Dart_Handle isolate_args[kNumIsolateArgs];
  isolate_args[0] = Dart_Null();   // parentPort
  isolate_args[1] = main_closure;  // entryPoint
  isolate_args[2] = runner->dart_options_->CreateRuntimeOptions();  // args
  isolate_args[3] = send_port;                                      // message
  isolate_args[4] = Dart_True();  // isSpawnUri
  isolate_args[5] = Dart_Null();  // controlPort
  isolate_args[6] = Dart_Null();  // capabilities

  Dart_Handle isolate_lib =
      Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
  Dart_Handle result =
      Dart_Invoke(isolate_lib, Dart_NewStringFromCString("_startIsolate"),
                  kNumIsolateArgs, isolate_args);
  CHECK_RESULT(result);
  CHECK_RESULT(Dart_RunLoop());

  Dart_CloseNativePort(send_port_id);

  Dart_ExitScope();
  Dart_ShutdownIsolate();
}

void DartDevIsolate::DartDevRunner::ProcessError(const char* msg,
                                                 int32_t exit_code) {
  Syslog::PrintErr("%s\n", msg);
  Process::SetGlobalExitCode(exit_code);
  result_ = DartDevIsolate::DartDev_Result_Exit;
  DartDevRunner::monitor_->Notify();
}

DartDevIsolate::DartDev_Result DartDevIsolate::RunDartDev(
    Dart_IsolateGroupCreateCallback create_isolate,
    const char* packages_file,
    char** script,
    CommandLineOptions* dart_options) {
  runner_.Run(create_isolate, packages_file, script, dart_options);
  return runner_.result();
}

#endif  // if !defined(DART_PRECOMPILED_RUNTIME)

}  // namespace bin
}  // namespace dart
<|endoftext|>


<commit_before>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>

TrackingWorker::TrackingWorker(IPositionReceiver *receiver)
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;

	while (!stop) {
		CameraData data = dequeue();

		if (data.valid) {
			ROS_DEBUG("Got valid data");
			receivedFirstPosition = true;
			Vector position = tracker.updatePosition(data.cameraVector, data.camNo, data.quadcopterId);

			std::vector<Vector> positions;
			std::vector<int> ids;
			std::vector<int> updates;
			positions.push_back(position);
			ids.push_back(data.quadcopterId);
			updates.push_back(1);

			if (position.isValid()) {
				receiver->updatePositions(positions, ids, updates);
			} else {
				ROS_DEBUG("Not enough information to get position of quadcopter %d", data.quadcopterId);
			}
		} else if (receivedFirstPosition == true) {
			ROS_WARN("Position update buffer is empty!");
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	enqueue(data);
}

void TrackingWorker::enqueue(CameraData data)
{
	ROS_DEBUG("Inserting CameraData");

	{
		boost::mutex::scoped_lock lock(positionsMutex);
		positions.push(data);

		if (positions.size() > 25) {
			ROS_WARN("Position update buffer is running full (%ld entries). Seems like the position updating can't keep up!", positions.size());
		}
	}

	ROS_DEBUG("Notifying about new CameraData");

	positionsEmpty.notify_one();

	ROS_DEBUG("Finished insertion process");
}

CameraData TrackingWorker::dequeue()
{
	ROS_DEBUG("Getting positions lock");

	{
		boost::mutex::scoped_lock lock(positionsMutex);

		ROS_DEBUG("Got positions lock");

		if (!dataAvailable()) {
			ROS_DEBUG("Waiting...");
			positionsEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
			ROS_DEBUG("Finished waiting");
		}

		if (dataAvailable()) {
			CameraData data = positions.back();
			positions.pop();
			return data;
		} else {
			CameraData data;
			data.valid = false;
			return data;
		}
	}

	ROS_DEBUG("Released positions lock");
}

bool TrackingWorker::dataAvailable()
{
	return positions.size() > 0;
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}<commit_msg>Uncommented debug output<commit_after>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>

TrackingWorker::TrackingWorker(IPositionReceiver *receiver)
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;

	while (!stop) {
		CameraData data = dequeue();

		if (data.valid) {
			// ROS_DEBUG("Got valid data");
			receivedFirstPosition = true;
			Vector position = tracker.updatePosition(data.cameraVector, data.camNo, data.quadcopterId);

			std::vector<Vector> positions;
			std::vector<int> ids;
			std::vector<int> updates;
			positions.push_back(position);
			ids.push_back(data.quadcopterId);
			updates.push_back(1);

			if (position.isValid()) {
				receiver->updatePositions(positions, ids, updates);
			} else {
				ROS_DEBUG("Not enough information to get position of quadcopter %d", data.quadcopterId);
			}
		} else if (receivedFirstPosition == true) {
			// ROS_WARN("Position update buffer is empty!");
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	enqueue(data);
}

void TrackingWorker::enqueue(CameraData data)
{
	// ROS_DEBUG("Inserting CameraData");

	{
		boost::mutex::scoped_lock lock(positionsMutex);
		positions.push(data);

		if (positions.size() > 25) {
			ROS_WARN("Position update buffer is running full (%ld entries). Seems like the position updating can't keep up!", positions.size());
		}
	}

	// ROS_DEBUG("Notifying about new CameraData");

	positionsEmpty.notify_one();

	// ROS_DEBUG("Finished insertion process");
}

CameraData TrackingWorker::dequeue()
{
	// ROS_DEBUG("Getting positions lock");

	{
		boost::mutex::scoped_lock lock(positionsMutex);

		// ROS_DEBUG("Got positions lock");

		if (!dataAvailable()) {
			positionsEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
		}

		if (dataAvailable()) {
			CameraData data = positions.back();
			positions.pop();
			return data;
		} else {
			CameraData data;
			data.valid = false;
			return data;
		}
	}

	// ROS_DEBUG("Released positions lock");
}

bool TrackingWorker::dataAvailable()
{
	return positions.size() > 0;
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}<|endoftext|>


<commit_before>
#pragma once

#include <memory>
#include <type_traits>

#include "base/macros.hpp"
#include "base/not_constructible.hpp"
#include "base/traits.hpp"
#include "glog/logging.h"

// This file defines a pointer wrapper |not_null| that statically ensures
// non-nullness where possible, and performs runtime checks at the point of
// conversion otherwise.
// The point is to replace cases of undefined behaviour (dereferencing a null
// pointer) by well-defined, localized, failure.
// For instance, when dereferencing a null pointer into a reference, a segfault
// will generally not occur when the pointer is dereferenced, but where the
// reference is used instead, making it hard to track where an invariant was
// violated.
// The static typing of |not_null| also optimizes away some unneeded checks:
// a function taking a |not_null| argument will not need to check its arguments,
// the caller has to provide a |not_null| pointer instead.  If the object passed
// is already a |not_null|, no check needs to be performed.
// The syntax is as follows:
//   not_null<int*> p  // non-null pointer to an |int|.
//   not_null<std::unique_ptr<int>> p // non-null unique pointer to an |int|.
// |not_null| does not have a default constructor, since there is no non-null
// default valid pointer.  The only ways to construct a |not_null| pointer,
// other than from existing instances of |not_null|, are (implicit) conversion
// from a nullable pointer, the factory |check_not_null|, and
// |make_not_null_unique|.
//
// The following example shows uses of |not_null|:
//   void Accumulate(not_null<int*> const accumulator,
//                   not_null<int const*> const term) {
//     *accumulator += *term;  // This will not dereference a null pointer.
//   }
//
//   void InterfaceAccumulator(int* const dubious_accumulator,
//                             int const* const term_of_dubious_c_provenance) {
//     // The call below performs two checks.  If either parameter is null, the
//     // program will fail (through a glog |CHECK|) at the callsite.
//     Accumulate(dubious_accumulator, term_of_dubious_c_provenance);
//   }
//
//   void UseAccumulator() {
//     not_null<std::unique_ptr<int>> accumulator =
//         make_not_null_unique<int>(0);
//     not_null<int> term = // ...
//     // This compiles, no check is performed.
//     Accumulate(accumulator.get(), term);
//     // ...
//   }
//
// If implicit conversion from a nullable pointer to |not_null| does not work,
// e.g. for template deduction, use the factory |check_not_null|.
//   template<typename T>
//   void Foo(not_null<T*> not_null_ptr);
//
//   SomeType* ptr;
//   // The following will not compile:
//   Foo(ptr);
//   // The following works:
//   Foo(check_not_null(ptr));
//   // It is more concise than the alternative:
//   Foo(not_null<SomeType*>(ptr))
//
// The following optimization is made possible by the use of |not_null|:
// |term == nullptr| can be expanded to false through inlining, so the branch
// will likely be optimized away.
//   if (term == nullptr) // ...
//   // Same as above.
//   if (term) // ...

namespace principia {
namespace base {

template<typename Pointer>
class not_null;

// Type traits.

// |remove_not_null<not_null<T>>::type| is |remove_not_null<T>::type|.
// The recurrence ends when |T| is not an instance of |not_null|, in which case
// |remove_not_null<T>::type| is |T|.
template<typename Pointer>
struct remove_not_null : not_constructible {
  using type = Pointer;
};
template<typename Pointer>
struct remove_not_null<not_null<Pointer>> {
  using type = typename remove_not_null<Pointer>::type;
};

// When |T| is not a reference, |_checked_not_null<T>| is |not_null<T>| if |T|
// is not already an instance of |not_null|.  It fails otherwise.
// |_checked_not_null| is invariant under application of reference or rvalue
// reference to its template argument.
template<typename Pointer>
using _checked_not_null = typename std::enable_if<
    !is_instance_of_v<not_null, typename std::remove_reference<Pointer>::type>,
    not_null<typename std::remove_reference<Pointer>::type>>::type;

// We cannot refer to the template |not_null| inside of |not_null|.
template<typename Pointer>
inline constexpr bool is_instance_of_not_null_v =
    is_instance_of_v<not_null, Pointer>;

// |not_null<Pointer>| is a wrapper for a non-null object of type |Pointer|.
// |Pointer| should be a C-style pointer or a smart pointer.  |Pointer| must not
// be a const, reference, rvalue reference, or |not_null|.  |not_null<Pointer>|
// is movable and may be left in an invalid state when moved, i.e., its
// |pointer_| may become null.
// |not_null<not_null<Pointer>>| and |not_null<Pointer>| are equivalent.
// This is useful when a |template<typename T>| using a |not_null<T>| is
// instanced with an instance of |not_null|.
template<typename Pointer>
class not_null final {
 public:
  // The type of the pointer being wrapped.
  // This follows the naming convention from |std::unique_ptr|.
  using pointer = typename remove_not_null<Pointer>::type;

  // Smart pointers define this type.
  using element_type = typename std::pointer_traits<pointer>::element_type;

  not_null() = delete;

  // Copy constructor from an other |not_null<Pointer>|.
  not_null(not_null const&) = default;
  // Copy contructor for implicitly convertible pointers.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null(not_null<OtherPointer> const& other);
  // Constructor from a nullable pointer, performs a null check.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value &&
               !is_instance_of_not_null_v<pointer>>::type>
  not_null(OtherPointer other);  // NOLINT(runtime/explicit)
  // Explicit copy constructor for static_cast'ing.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               !std::is_convertible<OtherPointer, pointer>::value>::type,
           typename = decltype(static_cast<pointer>(
                                   std::declval<OtherPointer>()))>
  explicit not_null(not_null<OtherPointer> const& other);

  // Move constructor from an other |not_null<Pointer>|.  This constructor may
  // invalidate its argument.
  not_null(not_null&&) = default;
  // Move contructor for implicitly convertible pointers. This constructor may
  // invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null(not_null<OtherPointer>&& other);
  // Explicit move constructor for static_cast'ing. This constructor may
  // invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               !std::is_convertible<OtherPointer, pointer>::value>::type,
           typename = decltype(static_cast<pointer>(
                                   std::declval<OtherPointer>()))>
  explicit not_null(not_null<OtherPointer>&& other);

  // Copy assigment operators.
  not_null& operator=(not_null const&) = default;
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null& operator=(not_null<OtherPointer> const& other);

  // Move assignment operators.
  // Implemented as a swap, so the argument remains valid.
  not_null& operator=(not_null&& other);
  // This operator may invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null& operator=(not_null<OtherPointer>&& other);

  // Returns |pointer_|, by const reference to avoid a copy if |pointer| is
  // |unique_ptr|.
  // If this were to return by |const&|, ambiguities would arise where an rvalue
  // of type |not_null<pointer>| is given as an argument to a function that has
  // overloads for both |pointer const&| and |pointer&&|.
  // Note that the preference for |T&&| over |T const&| for overload resolution
  // is not relevant here since both go through a user-defined conversion,
  // see 13.3.3.2.
  // GCC nevertheless incorrectly prefers |T&&| in that case, while clang and
  // MSVC recognize the ambiguity.
  // The |RValue| test gives two examples of this.
  operator pointer const&&() const&;

  template<typename OtherPointer,
           typename = std::enable_if_t<
               std::is_convertible<pointer, OtherPointer>::value &&
               !std::is_same<pointer, OtherPointer>::value &&
               !is_instance_of_not_null_v<OtherPointer>>>
  operator OtherPointer() const&;

  // Used to convert a |not_null<unique_ptr<>>| to |unique_ptr<>|.
  operator pointer&&() &&;

  template<typename OtherPointer,
           typename = std::enable_if_t<
               std::is_convertible<pointer, OtherPointer>::value &&
               !is_instance_of_not_null_v<OtherPointer>>>
  operator OtherPointer() &&;  // NOLINT(whitespace/operators)

  // Returns |*pointer_|.
  std::add_lvalue_reference_t<element_type> operator*() const;
  std::add_pointer_t<element_type> operator->() const;

  // When |pointer| has a |get()| member function, this returns
  // |pointer_.get()|.
  template<typename P = pointer, typename = decltype(std::declval<P>().get())>
  not_null<decltype(std::declval<P>().get())> get() const;

  // When |pointer| has a |release()| member function, this returns
  // |pointer_.release()|.  May invalidate its argument.
  template<typename P = pointer,
           typename = decltype(std::declval<P>().release())>
  not_null<decltype(std::declval<P>().release())> release();

  // When |pointer| has a |reset()| member function, this calls
  // |pointer_.reset()|.
  template<typename Q,
           typename P = pointer,
           typename = decltype(std::declval<P>().reset())>
  void reset(not_null<Q> ptr);

  // The following operators are redundant for valid |not_null<Pointer>|s with
  // the implicit conversion to |pointer|, but they should allow some
  // optimization.

  // Returns |false|.
  bool operator==(std::nullptr_t other) const;
  // Returns |true|.
  bool operator!=(std::nullptr_t other) const;
  // Returns |true|.
  operator bool() const;

  // Equality.
  bool operator==(pointer other) const;
  bool operator==(not_null other) const;
  bool operator!=(pointer other) const;
  bool operator!=(not_null other) const;

  // Ordering.
  bool operator<(not_null other) const;
  bool operator<=(not_null other) const;
  bool operator>=(not_null other) const;
  bool operator>(not_null other) const;

 private:
  struct unchecked_tag final {};

  // Creates a |not_null<Pointer>| whose |pointer_| equals the given |pointer|,
  // dawg.  The constructor does *not* perform a null check.  Callers must
  // perform one if needed before using it.
  explicit not_null(pointer other, unchecked_tag tag);

  pointer pointer_;

  static constexpr unchecked_tag unchecked_tag_{};

  template<typename OtherPointer>
  friend class not_null;

  template<typename P>
  friend _checked_not_null<P> check_not_null(P pointer);
  template<typename T, typename... Args>
  friend not_null<std::shared_ptr<T>> make_not_null_shared(Args&&... args);
  template<typename T, typename... Args>
  friend not_null<std::unique_ptr<T>> make_not_null_unique(Args&&... args);
};

// We want only one way of doing things, and we can't make
// |not_null<Pointer> const| and |not_null<Pointer const>| etc. equivalent
// easily.

// Use |not_null<Pointer> const| instead.
template<typename Pointer>
class not_null<Pointer const>;
// Use |not_null<Pointer>&| instead.
template<typename Pointer>
class not_null<Pointer&>;
// Use |not_null<Pointer>&&| instead.
template<typename Pointer>
class not_null<Pointer&&>;

// Factory taking advantage of template argument deduction.  Returns a
// |not_null<Pointer>| to |*pointer|.  |CHECK|s that |pointer| is not null.
template<typename Pointer>
_checked_not_null<Pointer> check_not_null(Pointer pointer);

#if 0
// While the above factory would cover this case using the implicit
// conversion, this results in a redundant |CHECK|.
// This function returns its argument.
template<typename Pointer>
not_null<Pointer> check_not_null(not_null<Pointer> pointer);
#endif

// Factory for a |not_null<std::unique_ptr<T>>|, forwards the arguments to the
// constructor of T.  |make_not_null_unique<T>(args)| is interchangeable with
// |check_not_null(make_unique<T>(args))|, but does not perform a |CHECK|, since
// the result of |make_unique| is not null.
template<typename T, typename... Args>
not_null<std::unique_ptr<T>> make_not_null_unique(Args&&... args);

// For logging.
template<typename Pointer>
std::ostream& operator<<(std::ostream& stream,
                         not_null<Pointer> const& pointer);

}  // namespace base
}  // namespace principia

#include "base/not_null_body.hpp"
<commit_msg>Embarrassing.<commit_after>
#pragma once

#include <memory>
#include <type_traits>

#include "base/macros.hpp"
#include "base/not_constructible.hpp"
#include "base/traits.hpp"
#include "glog/logging.h"

// This file defines a pointer wrapper |not_null| that statically ensures
// non-nullness where possible, and performs runtime checks at the point of
// conversion otherwise.
// The point is to replace cases of undefined behaviour (dereferencing a null
// pointer) by well-defined, localized, failure.
// For instance, when dereferencing a null pointer into a reference, a segfault
// will generally not occur when the pointer is dereferenced, but where the
// reference is used instead, making it hard to track where an invariant was
// violated.
// The static typing of |not_null| also optimizes away some unneeded checks:
// a function taking a |not_null| argument will not need to check its arguments,
// the caller has to provide a |not_null| pointer instead.  If the object passed
// is already a |not_null|, no check needs to be performed.
// The syntax is as follows:
//   not_null<int*> p  // non-null pointer to an |int|.
//   not_null<std::unique_ptr<int>> p // non-null unique pointer to an |int|.
// |not_null| does not have a default constructor, since there is no non-null
// default valid pointer.  The only ways to construct a |not_null| pointer,
// other than from existing instances of |not_null|, are (implicit) conversion
// from a nullable pointer, the factory |check_not_null|, and
// |make_not_null_unique|.
//
// The following example shows uses of |not_null|:
//   void Accumulate(not_null<int*> const accumulator,
//                   not_null<int const*> const term) {
//     *accumulator += *term;  // This will not dereference a null pointer.
//   }
//
//   void InterfaceAccumulator(int* const dubious_accumulator,
//                             int const* const term_of_dubious_c_provenance) {
//     // The call below performs two checks.  If either parameter is null, the
//     // program will fail (through a glog |CHECK|) at the callsite.
//     Accumulate(dubious_accumulator, term_of_dubious_c_provenance);
//   }
//
//   void UseAccumulator() {
//     not_null<std::unique_ptr<int>> accumulator =
//         make_not_null_unique<int>(0);
//     not_null<int> term = // ...
//     // This compiles, no check is performed.
//     Accumulate(accumulator.get(), term);
//     // ...
//   }
//
// If implicit conversion from a nullable pointer to |not_null| does not work,
// e.g. for template deduction, use the factory |check_not_null|.
//   template<typename T>
//   void Foo(not_null<T*> not_null_ptr);
//
//   SomeType* ptr;
//   // The following will not compile:
//   Foo(ptr);
//   // The following works:
//   Foo(check_not_null(ptr));
//   // It is more concise than the alternative:
//   Foo(not_null<SomeType*>(ptr))
//
// The following optimization is made possible by the use of |not_null|:
// |term == nullptr| can be expanded to false through inlining, so the branch
// will likely be optimized away.
//   if (term == nullptr) // ...
//   // Same as above.
//   if (term) // ...

namespace principia {
namespace base {

template<typename Pointer>
class not_null;

// Type traits.

// |remove_not_null<not_null<T>>::type| is |remove_not_null<T>::type|.
// The recurrence ends when |T| is not an instance of |not_null|, in which case
// |remove_not_null<T>::type| is |T|.
template<typename Pointer>
struct remove_not_null : not_constructible {
  using type = Pointer;
};
template<typename Pointer>
struct remove_not_null<not_null<Pointer>> {
  using type = typename remove_not_null<Pointer>::type;
};

// When |T| is not a reference, |_checked_not_null<T>| is |not_null<T>| if |T|
// is not already an instance of |not_null|.  It fails otherwise.
// |_checked_not_null| is invariant under application of reference or rvalue
// reference to its template argument.
template<typename Pointer>
using _checked_not_null = typename std::enable_if<
    !is_instance_of_v<not_null, typename std::remove_reference<Pointer>::type>,
    not_null<typename std::remove_reference<Pointer>::type>>::type;

// We cannot refer to the template |not_null| inside of |not_null|.
template<typename Pointer>
inline constexpr bool is_instance_of_not_null_v =
    is_instance_of_v<not_null, Pointer>;

// |not_null<Pointer>| is a wrapper for a non-null object of type |Pointer|.
// |Pointer| should be a C-style pointer or a smart pointer.  |Pointer| must not
// be a const, reference, rvalue reference, or |not_null|.  |not_null<Pointer>|
// is movable and may be left in an invalid state when moved, i.e., its
// |pointer_| may become null.
// |not_null<not_null<Pointer>>| and |not_null<Pointer>| are equivalent.
// This is useful when a |template<typename T>| using a |not_null<T>| is
// instanced with an instance of |not_null|.
template<typename Pointer>
class not_null final {
 public:
  // The type of the pointer being wrapped.
  // This follows the naming convention from |std::unique_ptr|.
  using pointer = typename remove_not_null<Pointer>::type;

  // Smart pointers define this type.
  using element_type = typename std::pointer_traits<pointer>::element_type;

  not_null() = delete;

  // Copy constructor from an other |not_null<Pointer>|.
  not_null(not_null const&) = default;
  // Copy contructor for implicitly convertible pointers.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null(not_null<OtherPointer> const& other);
  // Constructor from a nullable pointer, performs a null check.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value &&
               !is_instance_of_not_null_v<pointer>>::type>
  not_null(OtherPointer other);  // NOLINT(runtime/explicit)
  // Explicit copy constructor for static_cast'ing.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               !std::is_convertible<OtherPointer, pointer>::value>::type,
           typename = decltype(static_cast<pointer>(
                                   std::declval<OtherPointer>()))>
  explicit not_null(not_null<OtherPointer> const& other);

  // Move constructor from an other |not_null<Pointer>|.  This constructor may
  // invalidate its argument.
  not_null(not_null&&) = default;
  // Move contructor for implicitly convertible pointers. This constructor may
  // invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null(not_null<OtherPointer>&& other);
  // Explicit move constructor for static_cast'ing. This constructor may
  // invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               !std::is_convertible<OtherPointer, pointer>::value>::type,
           typename = decltype(static_cast<pointer>(
                                   std::declval<OtherPointer>()))>
  explicit not_null(not_null<OtherPointer>&& other);

  // Copy assigment operators.
  not_null& operator=(not_null const&) = default;
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null& operator=(not_null<OtherPointer> const& other);

  // Move assignment operators.
  // Implemented as a swap, so the argument remains valid.
  not_null& operator=(not_null&& other);
  // This operator may invalidate its argument.
  template<typename OtherPointer,
           typename = typename std::enable_if<
               std::is_convertible<OtherPointer, pointer>::value>::type>
  not_null& operator=(not_null<OtherPointer>&& other);

  // Returns |pointer_|, by const reference to avoid a copy if |pointer| is
  // |unique_ptr|.
  // If this were to return by |const&|, ambiguities would arise where an rvalue
  // of type |not_null<pointer>| is given as an argument to a function that has
  // overloads for both |pointer const&| and |pointer&&|.
  // Note that the preference for |T&&| over |T const&| for overload resolution
  // is not relevant here since both go through a user-defined conversion,
  // see 13.3.3.2.
  // GCC nevertheless incorrectly prefers |T&&| in that case, while clang and
  // MSVC recognize the ambiguity.
  // The |RValue| test gives two examples of this.
  operator pointer const&&() const&;

  template<typename OtherPointer,
           typename = std::enable_if_t<
               std::is_convertible<pointer, OtherPointer>::value &&
               !std::is_same<pointer, OtherPointer>::value &&
               !is_instance_of_not_null_v<OtherPointer>>>
  operator OtherPointer() const&;

  // Used to convert a |not_null<unique_ptr<>>| to |unique_ptr<>|.
  operator pointer&&() &&;

  template<typename OtherPointer,
           typename = std::enable_if_t<
               std::is_convertible<pointer, OtherPointer>::value &&
               !is_instance_of_not_null_v<OtherPointer>>>
  operator OtherPointer() &&;  // NOLINT(whitespace/operators)

  // Returns |*pointer_|.
  std::add_lvalue_reference_t<element_type> operator*() const;
  std::add_pointer_t<element_type> operator->() const;

  // When |pointer| has a |get()| member function, this returns
  // |pointer_.get()|.
  template<typename P = pointer, typename = decltype(std::declval<P>().get())>
  not_null<decltype(std::declval<P>().get())> get() const;

  // When |pointer| has a |release()| member function, this returns
  // |pointer_.release()|.  May invalidate its argument.
  template<typename P = pointer,
           typename = decltype(std::declval<P>().release())>
  not_null<decltype(std::declval<P>().release())> release();

  // When |pointer| has a |reset()| member function, this calls
  // |pointer_.reset()|.
  template<typename Q,
           typename P = pointer,
           typename = decltype(std::declval<P>().reset())>
  void reset(not_null<Q> ptr);

  // The following operators are redundant for valid |not_null<Pointer>|s with
  // the implicit conversion to |pointer|, but they should allow some
  // optimization.

  // Returns |false|.
  bool operator==(std::nullptr_t other) const;
  // Returns |true|.
  bool operator!=(std::nullptr_t other) const;
  // Returns |true|.
  operator bool() const;

  // Equality.
  bool operator==(pointer other) const;
  bool operator==(not_null other) const;
  bool operator!=(pointer other) const;
  bool operator!=(not_null other) const;

  // Ordering.
  bool operator<(not_null other) const;
  bool operator<=(not_null other) const;
  bool operator>=(not_null other) const;
  bool operator>(not_null other) const;

 private:
  struct unchecked_tag final {};

  // Creates a |not_null<Pointer>| whose |pointer_| equals the given |pointer|,
  // dawg.  The constructor does *not* perform a null check.  Callers must
  // perform one if needed before using it.
  explicit not_null(pointer other, unchecked_tag tag);

  pointer pointer_;

  static constexpr unchecked_tag unchecked_tag_{};

  template<typename OtherPointer>
  friend class not_null;

  template<typename P>
  friend _checked_not_null<P> check_not_null(P pointer);
  template<typename T, typename... Args>
  friend not_null<std::shared_ptr<T>> make_not_null_shared(Args&&... args);
  template<typename T, typename... Args>
  friend not_null<std::unique_ptr<T>> make_not_null_unique(Args&&... args);
};

// We want only one way of doing things, and we can't make
// |not_null<Pointer> const| and |not_null<Pointer const>| etc. equivalent
// easily.

// Use |not_null<Pointer> const| instead.
template<typename Pointer>
class not_null<Pointer const>;
// Use |not_null<Pointer>&| instead.
template<typename Pointer>
class not_null<Pointer&>;
// Use |not_null<Pointer>&&| instead.
template<typename Pointer>
class not_null<Pointer&&>;

// Factory taking advantage of template argument deduction.  Returns a
// |not_null<Pointer>| to |*pointer|.  |CHECK|s that |pointer| is not null.
template<typename Pointer>
_checked_not_null<Pointer> check_not_null(Pointer pointer);

#if 0
// While the above factory would cover this case using the implicit
// conversion, this results in a redundant |CHECK|.
// This function returns its argument.
template<typename Pointer>
not_null<Pointer> check_not_null(not_null<Pointer> pointer);
#endif

// Factory for a |not_null<std::unique_ptr<T>>|, forwards the arguments to the
// constructor of T.  |make_not_null_unique<T>(args)| is interchangeable with
// |check_not_null(make_unique<T>(args))|, but does not perform a |CHECK|, since
// the result of |make_unique| is not null.
template<typename T, typename... Args>
not_null<std::unique_ptr<T>> make_not_null_unique(Args&&... args);

// For logging.
template<typename Pointer>
std::ostream& operator<<(std::ostream& stream,
                         not_null<Pointer> const& pointer);

template<typename Result, typename T>
not_null<Result> dynamic_cast_not_null(not_null<T*> const pointer);

template<typename Result, typename T>
not_null<Result> dynamic_cast_not_null(not_null<std::unique_ptr<T>>&& pointer);

}  // namespace base
}  // namespace principia

#include "base/not_null_body.hpp"
<|endoftext|>