<commit_before>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#include "steve/parser.hpp"
#include "steve/builder.hpp"
#include "steve/lookup.hpp"

namespace steve
{

namespace
{

// -------------------------------------------------------------------------- //
//                            Variable declarations

// Parse a type clause.
//
//    type-clause ::= ':' type
Type const*
parse_type_clause(Parser& p, Token_stream& ts)
{
  if (expect_token(p, ts, colon_tok))
    return parse_type(p, ts);
  else
    return make_error_node<Type>();
}

// Parse an initializer clause. The initializer clause determines
// the initialization semantics of a variable declaration.
//
//    initializer-clause ::=
//        ';'
//      | '=' default ';'       # TODO
//      | '=' expression ';'
//      | '{' argument-list '}' # TODO
//      | '(' argument-list ')' # TODO
//
// TODO: Support aggregate initialization, possibly with
// designated initializers as in C+99.
Expr const*
parse_initializer_clause(Parser& p, Token_stream& ts)
{
  // Match default initialization
  if (Token const* tok = match_token(ts, semicolon_tok))
    return p.on_default_init(tok);

  // Match direct initialization
  if (Token const* tok = match_token(ts, equal_tok)) {
    if (Required<Expr> expr = parse_expr(p, ts)) {

      // Check for the trailing semicolon, but don't fail
      // outright if we can't find it. We can probably parse
      // the next statement without it.
      if (!match_token(ts, semicolon_tok))
        error("expected ';' after initializer");

      return p.on_direct_init(tok, *expr);
    } else {
      return make_error_node<Expr>();
    }
  }

  error("expected initializer-clause but got '{}'", ts.peek());
  return make_error_node<Expr>();
}

// Parse a variable declaration.
//
//    variable-declaration ::=
//        'var' identifier type-clause initializer-clause
Decl const*
parse_variable_decl(Parser& p, Token_stream& ts)
{
  Token const* tok = require_token(ts, var_kw);

  // Match the variable name.
  Token const* id = expect_token(p, ts, identifier_tok);
  if (!id)
    return make_error_node<Decl>();

  // Match the variable type.
  Required<Type> type = parse_type_clause(p, ts);
  if (!type)
    return make_error_node<Decl>();

  // Point of declaration. The variable is declared prior
  // to the initializer.
  Required<Decl> decl = p.on_variable_decl(tok, id, *type);
  if (!decl)
    return make_error_node<Decl>();

  // Match the initialzer.
  Required<Expr> init = parse_initializer_clause(p, ts);
  if (!init)
    return make_error_node<Decl>();

  return p.on_variable_init(*decl, *init);
}

// -------------------------------------------------------------------------- //
//                          Function declarations

// Parse a parameter declaration.
//
//    parameter-declaration ::= identifier type-clause
//
// TODO: Support default arguments.
Decl const*
parse_parameter_decl(Parser& p, Token_stream& ts)
{
  if (Token const* id = expect_token(p, ts, identifier_tok))
    if (Required<Type> type = parse_type_clause(p, ts))
      return p.on_parameter_decl(id, *type);
  return make_error_node<Decl>();
}

using Parm_seq = Sequence_term<Decl>;
using Parm_clause = Enclosed_term<Parm_seq>;

// Parse a parameter declaration list.
//
//    parameter-list ::= parameter-decl [',' parameter-decl]*
Parm_seq const*
parse_parameter_list(Parser& p, Token_stream& ts)
{
  return parse_list(p, ts, comma_tok, parse_parameter_decl);
}

// Parse a parameter clause.
//
//    parameter-clause ::= '(' parameter-list ')'
Parm_clause const*
parse_parameter_clause(Parser& p, Token_stream& ts)
{
  return parse_paren_enclosed(p, ts, parse_parameter_list);
}

// Parse a return clause.
//
//    return-clause ::= '-> type'
Type const*
parse_return_clause(Parser& p, Token_stream& ts)
{
  if (expect_token(p, ts, minus_gt_tok))
    return parse_type(p, ts);
  else
    return make_error_node<Type>();
}

// Represents a parsed function signature.
struct Signature : Term<>
{
  Signature(Decl_seq const& ps, Type const* t)
    : first(std::move(ps)), second(t)
  { }

  char const* node_name() const { return "signature"; }

  Decl_seq const& parms() const { return first; }
  Type const*     type() const { return second; }

  Decl_seq    first;
  Type const* second;
};

// Parse a function signature.
//
//    function-signature ::= parameter-clause return-clause
Signature const*
parse_signature(Parser& p, Token_stream& ts)
{
  if (Required<Parm_clause> c = parse_parameter_clause(p, ts))
    if (Required<Type> t = parse_return_clause(p, ts))  {
      // This invokes a copy. Moving would require const-casting.
      return gc().make<Signature>(*c->term(), *t);
    }
  return make_error_node<Signature>();
}

// Parse a function definition.
//
//    function-definition ::=
//        '=' expression ';'
//        block-stmt
//
// The definition of the form `= e` is equivalent to the function
// definition `{ return e; }`
Stmt const*
parse_function_def(Parser& p, Token_stream& ts)
{
  // Match a simple definition.
  if (match_token(ts, equal_tok)) {
    if (Required<Expr> expr = parse_expr(p, ts)) {

      // This is required, but we can probably continue
      // parsing without it.
      expect_token(p, ts, semicolon_tok);

      // TODO: Enclose in blocks?
      return p.on_return_stmt(*expr);
    }

  }
  error(ts.location(), "expected function-definition");
  return make_error_node<Stmt>();
}

// Parse a function definition.
//
//    function-declaration ::=
//        'def' identifier function-signature function-definition
//
//    return-clause ::= '->' type
Decl const*
parse_function_decl(Parser& p, Token_stream& ts)
{
  Token const* tok = require_token(ts, def_kw);

  // Match the function name.
  // TODO: Support operator overloading.
  Token const* id = expect_token(p, ts, identifier_tok);
  if (!id)
    return make_error_node<Decl>();

  // Match the function signature.
  Required<Signature> sig = parse_signature(p, ts);
  if (!sig)
    return make_error_node<Decl>();

  // Point of declaration. Declare the function in the
  // current scope.
  Decl_seq const& parms = sig->parms();
  Type const* ret = sig->type();
  Decl const* fn = p.on_function_decl(tok, id, parms, ret);

  // Enter function scope and declare the parameters.
  Stmt const* def;
  {
    Local_scope scope;
    if (!declare(parms))
      return make_error_node<Decl>();

    // Consume the function definition.
    Required<Stmt> body = parse_function_def(p, ts);
    if (!body)
      return make_error_node<Decl>();
    def = *body;
  }

  // Update the function definition.
  return p.on_function_def(fn, def);
}

// Parse decode body
//    decode-body ::-
//      block-stmt
Stmt const*
parse_decode_body(Parser& p, Token_stream& ts)
{

}

// Parse decode-decl
//    decode-decl ::=
//        'decode' identifier '('type-id')' [(optional) requires-clause] decode-body
Decl const*
parse_decode_decl(Parser& p, Token_stream& ts)
{
  return nullptr;
}

// Parse table-initializer
//    table-initializer ::=
//        '{' flow-decl, ... '}'
Decl_seq const&
parse_table_initializer(Parser& p, Token_stream& ts)
{

}

// Parse table-key-fields
//    table-key-fields ::=
//        '<' dot-expr, dot-expr,... '>'
Expr_seq const&
parse_key_field(Parser& p, Token_stream& ts)
{

}

// Parse table declarations
//    table-declaration ::=
//        'table' identifier table-key-fields table-initializer
Decl const*
parse_table_decl(Parser& p, Token_stream& ts)
{
  return nullptr;
}

} // namespace

// Parse a top-level declaration.
//
//    declaration ::=
//        variable-decl
//        function-decl
//        decode-decl
//        table-decl
//
// Note that this is only called from the statement parser.
// We are guaranteed to match a top-level declaration here.
Decl const*
parse_decl(Parser& p, Token_stream& ts)
{
  switch (next_token_kind(ts)) {
    case var_kw:
      return parse_variable_decl(p, ts);
    case def_kw:
      return parse_function_decl(p, ts);
    case decode_kw:
      return parse_decode_decl(p, ts);
    case table_kw:
      return parse_table_decl(p, ts);

    default:
      break;
  }
  lingo_unreachable();
}

Decl const*
parse_decl(Token_stream& ts)
{
  Parser p;
  return parse_decl(p, ts);
}

} // namespace steve

<commit_msg>flow decl stub<commit_after>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#include "steve/parser.hpp"
#include "steve/builder.hpp"
#include "steve/lookup.hpp"

namespace steve
{

namespace
{

// -------------------------------------------------------------------------- //
//                            Variable declarations

// Parse a type clause.
//
//    type-clause ::= ':' type
Type const*
parse_type_clause(Parser& p, Token_stream& ts)
{
  if (expect_token(p, ts, colon_tok))
    return parse_type(p, ts);
  else
    return make_error_node<Type>();
}

// Parse an initializer clause. The initializer clause determines
// the initialization semantics of a variable declaration.
//
//    initializer-clause ::=
//        ';'
//      | '=' default ';'       # TODO
//      | '=' expression ';'
//      | '{' argument-list '}' # TODO
//      | '(' argument-list ')' # TODO
//
// TODO: Support aggregate initialization, possibly with
// designated initializers as in C+99.
Expr const*
parse_initializer_clause(Parser& p, Token_stream& ts)
{
  // Match default initialization
  if (Token const* tok = match_token(ts, semicolon_tok))
    return p.on_default_init(tok);

  // Match direct initialization
  if (Token const* tok = match_token(ts, equal_tok)) {
    if (Required<Expr> expr = parse_expr(p, ts)) {

      // Check for the trailing semicolon, but don't fail
      // outright if we can't find it. We can probably parse
      // the next statement without it.
      if (!match_token(ts, semicolon_tok))
        error("expected ';' after initializer");

      return p.on_direct_init(tok, *expr);
    } else {
      return make_error_node<Expr>();
    }
  }

  error("expected initializer-clause but got '{}'", ts.peek());
  return make_error_node<Expr>();
}

// Parse a variable declaration.
//
//    variable-declaration ::=
//        'var' identifier type-clause initializer-clause
Decl const*
parse_variable_decl(Parser& p, Token_stream& ts)
{
  Token const* tok = require_token(ts, var_kw);

  // Match the variable name.
  Token const* id = expect_token(p, ts, identifier_tok);
  if (!id)
    return make_error_node<Decl>();

  // Match the variable type.
  Required<Type> type = parse_type_clause(p, ts);
  if (!type)
    return make_error_node<Decl>();

  // Point of declaration. The variable is declared prior
  // to the initializer.
  Required<Decl> decl = p.on_variable_decl(tok, id, *type);
  if (!decl)
    return make_error_node<Decl>();

  // Match the initialzer.
  Required<Expr> init = parse_initializer_clause(p, ts);
  if (!init)
    return make_error_node<Decl>();

  return p.on_variable_init(*decl, *init);
}

// -------------------------------------------------------------------------- //
//                          Function declarations

// Parse a parameter declaration.
//
//    parameter-declaration ::= identifier type-clause
//
// TODO: Support default arguments.
Decl const*
parse_parameter_decl(Parser& p, Token_stream& ts)
{
  if (Token const* id = expect_token(p, ts, identifier_tok))
    if (Required<Type> type = parse_type_clause(p, ts))
      return p.on_parameter_decl(id, *type);
  return make_error_node<Decl>();
}

using Parm_seq = Sequence_term<Decl>;
using Parm_clause = Enclosed_term<Parm_seq>;

// Parse a parameter declaration list.
//
//    parameter-list ::= parameter-decl [',' parameter-decl]*
Parm_seq const*
parse_parameter_list(Parser& p, Token_stream& ts)
{
  return parse_list(p, ts, comma_tok, parse_parameter_decl);
}

// Parse a parameter clause.
//
//    parameter-clause ::= '(' parameter-list ')'
Parm_clause const*
parse_parameter_clause(Parser& p, Token_stream& ts)
{
  return parse_paren_enclosed(p, ts, parse_parameter_list);
}

// Parse a return clause.
//
//    return-clause ::= '-> type'
Type const*
parse_return_clause(Parser& p, Token_stream& ts)
{
  if (expect_token(p, ts, minus_gt_tok))
    return parse_type(p, ts);
  else
    return make_error_node<Type>();
}

// Represents a parsed function signature.
struct Signature : Term<>
{
  Signature(Decl_seq const& ps, Type const* t)
    : first(std::move(ps)), second(t)
  { }

  char const* node_name() const { return "signature"; }

  Decl_seq const& parms() const { return first; }
  Type const*     type() const { return second; }

  Decl_seq    first;
  Type const* second;
};

// Parse a function signature.
//
//    function-signature ::= parameter-clause return-clause
Signature const*
parse_signature(Parser& p, Token_stream& ts)
{
  if (Required<Parm_clause> c = parse_parameter_clause(p, ts))
    if (Required<Type> t = parse_return_clause(p, ts))  {
      // This invokes a copy. Moving would require const-casting.
      return gc().make<Signature>(*c->term(), *t);
    }
  return make_error_node<Signature>();
}

// Parse a function definition.
//
//    function-definition ::=
//        '=' expression ';'
//        block-stmt
//
// The definition of the form `= e` is equivalent to the function
// definition `{ return e; }`
Stmt const*
parse_function_def(Parser& p, Token_stream& ts)
{
  // Match a simple definition.
  if (match_token(ts, equal_tok)) {
    if (Required<Expr> expr = parse_expr(p, ts)) {

      // This is required, but we can probably continue
      // parsing without it.
      expect_token(p, ts, semicolon_tok);

      // TODO: Enclose in blocks?
      return p.on_return_stmt(*expr);
    }

  }
  error(ts.location(), "expected function-definition");
  return make_error_node<Stmt>();
}

// Parse a function definition.
//
//    function-declaration ::=
//        'def' identifier function-signature function-definition
//
//    return-clause ::= '->' type
Decl const*
parse_function_decl(Parser& p, Token_stream& ts)
{
  Token const* tok = require_token(ts, def_kw);

  // Match the function name.
  // TODO: Support operator overloading.
  Token const* id = expect_token(p, ts, identifier_tok);
  if (!id)
    return make_error_node<Decl>();

  // Match the function signature.
  Required<Signature> sig = parse_signature(p, ts);
  if (!sig)
    return make_error_node<Decl>();

  // Point of declaration. Declare the function in the
  // current scope.
  Decl_seq const& parms = sig->parms();
  Type const* ret = sig->type();
  Decl const* fn = p.on_function_decl(tok, id, parms, ret);

  // Enter function scope and declare the parameters.
  Stmt const* def;
  {
    Local_scope scope;
    if (!declare(parms))
      return make_error_node<Decl>();

    // Consume the function definition.
    Required<Stmt> body = parse_function_def(p, ts);
    if (!body)
      return make_error_node<Decl>();
    def = *body;
  }

  // Update the function definition.
  return p.on_function_def(fn, def);
}

// Parse decode body
//    decode-body ::-
//      block-stmt
Stmt const*
parse_decode_body(Parser& p, Token_stream& ts)
{

}

// Parse decode-decl
//    decode-decl ::=
//        'decode' identifier '('type-id')' [(optional) requires-clause] decode-body
Decl const*
parse_decode_decl(Parser& p, Token_stream& ts)
{
  return nullptr;
}

// Parse flow declaration
//    flow-declaration ::=
//        <dot-expr, ....> => block-stmt
Decl const*
parse_flow_decl(Parser& p, Token_stream& ts)
{
  return nullptr;
}

// Parse table-initializer
//    table-initializer ::=
//        '{' flow-decl, ... '}'
Decl_seq const&
parse_table_initializer(Parser& p, Token_stream& ts)
{

}

// Parse table-key-fields
//    table-key-fields ::=
//        '<' dot-expr, dot-expr,... '>'
Expr_seq const&
parse_key_field(Parser& p, Token_stream& ts)
{

}

// Parse table declarations
//    table-declaration ::=
//        'table' identifier table-key-fields table-initializer
Decl const*
parse_table_decl(Parser& p, Token_stream& ts)
{
  return nullptr;
}

} // namespace

// Parse a top-level declaration.
//
//    declaration ::=
//        variable-decl
//        function-decl
//        decode-decl
//        table-decl
//
// Note that this is only called from the statement parser.
// We are guaranteed to match a top-level declaration here.
Decl const*
parse_decl(Parser& p, Token_stream& ts)
{
  switch (next_token_kind(ts)) {
    case var_kw:
      return parse_variable_decl(p, ts);
    case def_kw:
      return parse_function_decl(p, ts);
    case decode_kw:
      return parse_decode_decl(p, ts);
    case table_kw:
      return parse_table_decl(p, ts);

    default:
      break;
  }
  lingo_unreachable();
}

Decl const*
parse_decl(Token_stream& ts)
{
  Parser p;
  return parse_decl(p, ts);
}

} // namespace steve

<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <vistk/pipeline/config.h>
#include <vistk/pipeline/modules.h>
#include <vistk/pipeline/process.h>
#include <vistk/pipeline/process_exception.h>
#include <vistk/pipeline/process_registry.h>
#include <vistk/pipeline/process_registry_exception.h>
#include <vistk/pipeline/types.h>

#include <boost/foreach.hpp>

#include <exception>
#include <iostream>

int
main()
{
  vistk::process_registry_t reg = vistk::process_registry::self();

  try
  {
    vistk::load_known_modules();
  }
  catch (vistk::process_type_already_exists_exception& e)
  {
    std::cerr << "Error: Duplicate process names: " << e.what() << std::endl;
  }
  catch (vistk::pipeline_exception& e)
  {
    std::cerr << "Error: Failed to load modules: " << e.what() << std::endl;
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: Unexpected exception when loading modules: " << e.what() << std::endl;

    return 1;
  }

  vistk::process::name_t const expected_name = vistk::process::name_t("expected_name");

  vistk::process_registry::types_t const types = reg->types();

  vistk::config_t config = vistk::config::empty_config();
  config->set_value(vistk::process::config_name, expected_name);

  BOOST_FOREACH (vistk::process_registry::type_t const& type, types)
  {
    vistk::process_t process;

    try
    {
      process = reg->create_process(type, config);
    }
    catch (vistk::no_such_process_type_exception& e)
    {
      std::cerr << "Error: Failed to create process: " << e.what() << std::endl;

      continue;
    }
    catch (std::exception& e)
    {
      std::cerr << "Error: Unexpected exception when creating process: " << e.what() << std::endl;
    }

    if (!process)
    {
      std::cerr << "Error: Received NULL process (" << type << ")" << std::endl;

      continue;
    }

    if (reg->description(type).empty())
    {
      std::cerr << "Error: The description is empty" << std::endl;
    }

    if (process->name() != expected_name)
    {
      std::cerr << "Error: Name (" << process->name() << ") "
                << "does not match expected name: " << expected_name << std::endl;
    }

    if (process->type().empty())
    {
      std::cerr << "Error: The type is empty" << std::endl;
    }

    vistk::config::keys_t const keys = process->available_config();

    BOOST_FOREACH (vistk::config::key_t const& key, keys)
    {
      try
      {
        process->config_default(key);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
        std::cerr << "Error: Failed to get a default for "
                  << type << vistk::config::block_sep << key
                  << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for default "
                  << "(" << type << vistk::config::block_sep
                  << key << "): " << e.what() << std::endl;
      }

      try
      {
        process->config_description(key);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
        std::cerr << "Error: Failed to get a description for "
                  << type << vistk::config::block_sep << key
                  << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for description "
                  << "(" << type << vistk::config::block_sep
                  << key << "): " << e.what() << std::endl;
      }
    }

    vistk::process::ports_t const iports = process->input_ports();

    BOOST_FOREACH (vistk::process::port_t const& port, iports)
    {
      try
      {
        process->input_port_type(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a type for input port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for input port type "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }

      try
      {
        process->input_port_description(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a description for input port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for input port description "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }
    }

    vistk::process::ports_t const oports = process->output_ports();

    BOOST_FOREACH (vistk::process::port_t const& port, oports)
    {
      try
      {
        process->output_port_type(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a type for output port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for output port type "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }

      try
      {
        process->output_port_description(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a description for output port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for output port description "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }
    }

    // Test for proper exceptions on invalid config requests.
    {
      vistk::config::key_t const non_existent_config = vistk::config::key_t("does_not_exist");

      try
      {
        process->config_default(non_existent_config);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when "
                  << "requesting default for non-existent config: "
                  << e.what() << std::endl;
      }

      try
      {
        process->config_description(non_existent_config);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when "
                  << "requesting description for non-existent config: "
                  << e.what() << std::endl;
      }
    }

    // Test for proper exceptions on invalid port requests.
    {
      vistk::process::port_t const non_existent_port = vistk::process::port_t("does_not_exist");

      // Input ports.
      {
        try
        {
          process->input_port_type(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting type on non-existent input port: "
                    << e.what() << std::endl;
        }

        try
        {
          process->input_port_description(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting description for non-existent input port: "
                    << e.what() << std::endl;
        }

        vistk::edge_t edge = vistk::edge_t(new vistk::edge(config));

        try
        {
          process->connect_input_port(non_existent_port, edge);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting connection to non-existent input port: "
                    << e.what() << std::endl;
        }
      }

      // Output ports.
      {
        try
        {
          process->output_port_type(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting type on non-existent output port: "
                    << e.what() << std::endl;
        }

        try
        {
          process->output_port_description(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting description for non-existent output port: "
                    << e.what() << std::endl;
        }

        vistk::edge_t edge = vistk::edge_t(new vistk::edge(config));

        try
        {
          process->connect_output_port(non_existent_port, edge);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting connection to non-existent output port: "
                    << e.what() << std::endl;
        }
      }
    }
  }

  return 0;
}
<commit_msg>Check exceptions for unknown process types<commit_after>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <vistk/pipeline/config.h>
#include <vistk/pipeline/modules.h>
#include <vistk/pipeline/process.h>
#include <vistk/pipeline/process_exception.h>
#include <vistk/pipeline/process_registry.h>
#include <vistk/pipeline/process_registry_exception.h>
#include <vistk/pipeline/types.h>

#include <boost/foreach.hpp>

#include <exception>
#include <iostream>

int
main()
{
  vistk::process_registry_t reg = vistk::process_registry::self();

  try
  {
    vistk::load_known_modules();
  }
  catch (vistk::process_type_already_exists_exception& e)
  {
    std::cerr << "Error: Duplicate process names: " << e.what() << std::endl;
  }
  catch (vistk::pipeline_exception& e)
  {
    std::cerr << "Error: Failed to load modules: " << e.what() << std::endl;
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: Unexpected exception when loading modules: " << e.what() << std::endl;

    return 1;
  }

  vistk::process::name_t const expected_name = vistk::process::name_t("expected_name");

  vistk::process_registry::types_t const types = reg->types();

  vistk::config_t config = vistk::config::empty_config();
  config->set_value(vistk::process::config_name, expected_name);

  BOOST_FOREACH (vistk::process_registry::type_t const& type, types)
  {
    vistk::process_t process;

    try
    {
      process = reg->create_process(type, config);
    }
    catch (vistk::no_such_process_type_exception& e)
    {
      std::cerr << "Error: Failed to create process: " << e.what() << std::endl;

      continue;
    }
    catch (std::exception& e)
    {
      std::cerr << "Error: Unexpected exception when creating process: " << e.what() << std::endl;
    }

    if (!process)
    {
      std::cerr << "Error: Received NULL process (" << type << ")" << std::endl;

      continue;
    }

    if (reg->description(type).empty())
    {
      std::cerr << "Error: The description is empty" << std::endl;
    }

    if (process->name() != expected_name)
    {
      std::cerr << "Error: Name (" << process->name() << ") "
                << "does not match expected name: " << expected_name << std::endl;
    }

    if (process->type().empty())
    {
      std::cerr << "Error: The type is empty" << std::endl;
    }

    vistk::config::keys_t const keys = process->available_config();

    BOOST_FOREACH (vistk::config::key_t const& key, keys)
    {
      try
      {
        process->config_default(key);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
        std::cerr << "Error: Failed to get a default for "
                  << type << vistk::config::block_sep << key
                  << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for default "
                  << "(" << type << vistk::config::block_sep
                  << key << "): " << e.what() << std::endl;
      }

      try
      {
        process->config_description(key);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
        std::cerr << "Error: Failed to get a description for "
                  << type << vistk::config::block_sep << key
                  << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for description "
                  << "(" << type << vistk::config::block_sep
                  << key << "): " << e.what() << std::endl;
      }
    }

    vistk::process::ports_t const iports = process->input_ports();

    BOOST_FOREACH (vistk::process::port_t const& port, iports)
    {
      try
      {
        process->input_port_type(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a type for input port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for input port type "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }

      try
      {
        process->input_port_description(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a description for input port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for input port description "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }
    }

    vistk::process::ports_t const oports = process->output_ports();

    BOOST_FOREACH (vistk::process::port_t const& port, oports)
    {
      try
      {
        process->output_port_type(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a type for output port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for output port type "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }

      try
      {
        process->output_port_description(port);
      }
      catch (vistk::no_such_port_exception& e)
      {
        std::cerr << "Error: Failed to get a description for output port "
                  << type << "." << port << ": " << e.what() << std::endl;
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when querying for output port description "
                  << "(" << type << "." << port << "): " << e.what() << std::endl;
      }
    }

    // Test for proper exceptions on invalid config requests.
    {
      vistk::config::key_t const non_existent_config = vistk::config::key_t("does_not_exist");

      try
      {
        process->config_default(non_existent_config);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when "
                  << "requesting default for non-existent config: "
                  << e.what() << std::endl;
      }

      try
      {
        process->config_description(non_existent_config);
      }
      catch (vistk::unknown_configuration_value_exception& e)
      {
      }
      catch (std::exception& e)
      {
        std::cerr << "Error: Unexpected exception when "
                  << "requesting description for non-existent config: "
                  << e.what() << std::endl;
      }
    }

    // Test for proper exceptions on invalid port requests.
    {
      vistk::process::port_t const non_existent_port = vistk::process::port_t("does_not_exist");

      // Input ports.
      {
        try
        {
          process->input_port_type(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting type on non-existent input port: "
                    << e.what() << std::endl;
        }

        try
        {
          process->input_port_description(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting description for non-existent input port: "
                    << e.what() << std::endl;
        }

        vistk::edge_t edge = vistk::edge_t(new vistk::edge(config));

        try
        {
          process->connect_input_port(non_existent_port, edge);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting connection to non-existent input port: "
                    << e.what() << std::endl;
        }
      }

      // Output ports.
      {
        try
        {
          process->output_port_type(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting type on non-existent output port: "
                    << e.what() << std::endl;
        }

        try
        {
          process->output_port_description(non_existent_port);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting description for non-existent output port: "
                    << e.what() << std::endl;
        }

        vistk::edge_t edge = vistk::edge_t(new vistk::edge(config));

        try
        {
          process->connect_output_port(non_existent_port, edge);
        }
        catch (vistk::no_such_port_exception& e)
        {
        }
        catch (std::exception& e)
        {
          std::cerr << "Error: Unexpected exception when "
                    << "requesting connection to non-existent output port: "
                    << e.what() << std::endl;
        }
      }
    }
  }

  // Check exceptions for unknown types.
  {
    vistk::process_registry::type_t const non_existent_process = vistk::process_registry::type_t("no_such_process");

    try
    {
      reg->create_process(non_existent_process, config);
    }
    catch (vistk::no_such_process_type_exception& e)
    {
    }
    catch (std::exception& e)
    {
      std::cerr << "Error: Unexpected exception when "
                << "requesting a non-existent process type: "
                << e.what() << std::endl;
    }

    try
    {
      reg->description(non_existent_process);
    }
    catch (vistk::no_such_process_type_exception& e)
    {
    }
    catch (std::exception& e)
    {
      std::cerr << "Error: Unexpected exception when "
                << "requesting a description of a non-existent process type: "
                << e.what() << std::endl;
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/Lazy.hpp"
#include "libbirch/Shared.hpp"
#include "libbirch/FiberState.hpp"
#include "libbirch/Optional.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam Return Return type.
 * @tparam Yield Yield type.
 */
template<class Return, class Yield>
class Fiber {
public:
  using return_type = Return;
  using yield_type = Yield;
  using state_type = Lazy<Shared<FiberState<Return,Yield>>>;

  /**
   * Constructor. Used:
   *
   * @li for an uninitialized fiber handle, and
   * @li for returns in fibers with a return type of `void`, where no state
   * or resume function is required, and no value is returned.
   */
  Fiber() = default;

  /**
   * Constructor. Used:
   *
   * @li in the initialization function of all fibers, where a state and
   * start function are required, but no value is yielded, and
   * @li for yields in fibers with a yield type of `void`, where a state and
   * resume function are required, but no value is yielded.
   */
  Fiber(state_type&& state) :
      state(std::move(state)) {
    //
  }

  /**
   * Constructor. Used for yields in fibers with a yield type that is not
   * `void`, where a state and resume function are required, along with a
   * yield value.
   */
  Fiber(yield_type&& yieldValue, state_type&& state) :
      yieldValue(std::move(yieldValue)),
      state(std::move(state)) {
    //
  }

  /**
   * Constructor. Used for returns in fibers with a return type that is not
   * `void`, where a state and resume function are not required, and a value
   * is returned.
   */
  Fiber(return_type&& returnValue) :
      returnValue(std::move(returnValue)) {
    //
  }

  /**
   * Accept visitor.
   */
  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(returnValue, yieldValue, state);
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() {
    returnValue = nil;
    yieldValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  /**
   * Get the current yield value.
   */
  auto& get() const {
    return yieldValue.get();
  }

  /**
   * Get the current return value.
   */
  auto& getReturn() const {
    return returnValue.get();
  }

private:
  /**
   * Return value.
   */
  Optional<return_type> returnValue;

  /**
   * Yield value.
   */
  Optional<yield_type> yieldValue;

  /**
   * Fiber state.
   */
  Optional<state_type> state;
};

template<class Return>
class Fiber<Return,void> {
public:
  using return_type = Return;
  using yield_type = void;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(state_type&& state) :
      state(std::move(state)) {
    //
  }

  Fiber(return_type&& returnValue) :
      returnValue(std::move(returnValue)) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(returnValue, state);
  }

  bool query() {
    returnValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  auto& getReturn() const {
    return returnValue.get();
  }

private:
  Optional<return_type> returnValue;
  Optional<state_type> state;
};

template<class Yield>
class Fiber<void,Yield> {
public:
  using return_type = void;
  using yield_type = Yield;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(state_type&& state) :
      state(std::move(state)) {
    //
  }

  Fiber(yield_type&& yieldValue, state_type&& state) :
      yieldValue(std::move(yieldValue)),
      state(std::move(state)) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(yieldValue, state);
  }

  bool query() {
    yieldValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  auto& get() const {
    return yieldValue.get();
  }

  void getReturn() const {
    //
  }

private:
  Optional<yield_type> yieldValue;
  Optional<state_type> state;
};

template<>
class Fiber<void,void> {
public:
  using return_type = void;
  using yield_type = void;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(state_type&& state) :
      state(std::move(state)) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(state);
  }

  bool query() {
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  void getReturn() const {
    //
  }

private:
  Optional<state_type> state;
};

template<class Return, class Yield>
struct is_value<Fiber<Return,Yield>> {
  static const bool value = false;
};

template<class Return, class Yield, unsigned N>
struct is_acyclic<Fiber<Return,Yield>,N> {
  // Fiber is type-erased; no access to state to guarantee this
  static const bool value = false;
};

template<class Return, class Yield>
auto canonical(const Fiber<Return,Yield>& o) {
  return o;
}

template<class Return, class Yield>
auto canonical(Fiber<Return,Yield>&& o) {
  return std::move(o);
}

}
<commit_msg>Removed use of rvalue references in initializing fibers; causing problems with gcc.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/Lazy.hpp"
#include "libbirch/Shared.hpp"
#include "libbirch/FiberState.hpp"
#include "libbirch/Optional.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam Return Return type.
 * @tparam Yield Yield type.
 */
template<class Return, class Yield>
class Fiber {
public:
  using return_type = Return;
  using yield_type = Yield;
  using state_type = Lazy<Shared<FiberState<Return,Yield>>>;

  /**
   * Constructor. Used:
   *
   * @li for an uninitialized fiber handle, and
   * @li for returns in fibers with a return type of `void`, where no state
   * or resume function is required, and no value is returned.
   */
  Fiber() = default;

  /**
   * Constructor. Used:
   *
   * @li in the initialization function of all fibers, where a state and
   * start function are required, but no value is yielded, and
   * @li for yields in fibers with a yield type of `void`, where a state and
   * resume function are required, but no value is yielded.
   */
  Fiber(const state_type& state) :
      state(state) {
    //
  }

  /**
   * Constructor. Used for yields in fibers with a yield type that is not
   * `void`, where a state and resume function are required, along with a
   * yield value.
   */
  Fiber(const yield_type& yieldValue, const state_type& state) :
      yieldValue(yieldValue),
      state(state) {
    //
  }

  /**
   * Constructor. Used for returns in fibers with a return type that is not
   * `void`, where a state and resume function are not required, and a value
   * is returned.
   */
  Fiber(const return_type& returnValue) :
      returnValue(returnValue) {
    //
  }

  /**
   * Accept visitor.
   */
  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(returnValue, yieldValue, state);
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() {
    returnValue = nil;
    yieldValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  /**
   * Get the current yield value.
   */
  auto& get() const {
    return yieldValue.get();
  }

  /**
   * Get the current return value.
   */
  auto& getReturn() const {
    return returnValue.get();
  }

private:
  /**
   * Return value.
   */
  Optional<return_type> returnValue;

  /**
   * Yield value.
   */
  Optional<yield_type> yieldValue;

  /**
   * Fiber state.
   */
  Optional<state_type> state;
};

template<class Return>
class Fiber<Return,void> {
public:
  using return_type = Return;
  using yield_type = void;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(const state_type& state) :
      state(state) {
    //
  }

  Fiber(const return_type& returnValue) :
      returnValue(returnValue) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(returnValue, state);
  }

  bool query() {
    returnValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  auto& getReturn() const {
    return returnValue.get();
  }

private:
  Optional<return_type> returnValue;
  Optional<state_type> state;
};

template<class Yield>
class Fiber<void,Yield> {
public:
  using return_type = void;
  using yield_type = Yield;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(const state_type& state) :
      state(state) {
    //
  }

  Fiber(const yield_type& yieldValue, const state_type& state) :
      yieldValue(yieldValue),
      state(state) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(yieldValue, state);
  }

  bool query() {
    yieldValue = nil;
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  auto& get() const {
    return yieldValue.get();
  }

  void getReturn() const {
    //
  }

private:
  Optional<yield_type> yieldValue;
  Optional<state_type> state;
};

template<>
class Fiber<void,void> {
public:
  using return_type = void;
  using yield_type = void;
  using state_type = Lazy<Shared<FiberState<return_type,yield_type>>>;

  Fiber() = default;

  Fiber(const state_type& state) :
      state(state) {
    //
  }

  template<class Visitor>
  void accept_(const Visitor& v) {
    v.visit(state);
  }

  bool query() {
    if (state.query()) {
      *this = state.get()->query();
    }
    return state.query();
  }

  bool query() const {
    return const_cast<Fiber*>(this)->query();
  }

  void getReturn() const {
    //
  }

private:
  Optional<state_type> state;
};

template<class Return, class Yield>
struct is_value<Fiber<Return,Yield>> {
  static const bool value = false;
};

template<class Return, class Yield, unsigned N>
struct is_acyclic<Fiber<Return,Yield>,N> {
  // Fiber is type-erased; no access to state to guarantee this
  static const bool value = false;
};

template<class Return, class Yield>
auto canonical(const Fiber<Return,Yield>& o) {
  return o;
}

template<class Return, class Yield>
auto canonical(Fiber<Return,Yield>&& o) {
  return std::move(o);
}

}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *  Copyright (C) 2020  The Symbiflow Authors
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "pcf_parser.hh"
#include "pinmap_parser.hh"

#include "kernel/register.h"
#include "kernel/rtlil.h"

#include <regex>
#include <sstream>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

void register_in_tcl_interpreter(const std::string& command) {
    Tcl_Interp* interp = yosys_get_tcl_interp();
    std::string tcl_script = stringf("proc %s args { return [yosys %s {*}$args] }", command.c_str(), command.c_str());
    Tcl_Eval(interp, tcl_script.c_str());
}

struct QuicklogicIob : public Pass {

    struct IoCellType {
        std::string type;                        // Cell type
        std::string port;                        // Name of the port that goes to a pad
        std::vector<std::string> preferredTypes; // A list of preferred IO cell types

        IoCellType (const std::string& _type, const std::string& _port, const std::vector<std::string> _preferredTypes = std::vector<std::string>()) :
            type(_type),
            port(_port),
            preferredTypes(_preferredTypes)
        {}
    };

    QuicklogicIob () :
        Pass("quicklogic_iob", "Map IO buffers to cells that correspond to their assigned locations") {
            register_in_tcl_interpreter(pass_name);
        }

    void help() YS_OVERRIDE {
        log("\n");
        log("    quicklogic_iob <PCF file> <pinmap file> [<io cell specs>]");
        log("\n");
        log("This command assigns certain parameters of the specified IO cell types\n");
        log("basing on the placement constraints and the pin map of the target device\n");
        log("\n");
        log("Each affected IO cell is assigned the followin parameters:\n");
        log(" - IO_PAD  = \"<IO pad name>\"\n");
        log(" - IO_LOC  = \"<IO cell location>\"\n");
        log(" - IO_CELL = \"<IO cell type>\"\n");
        log("\n");
        log("Parameters:\n");
        log("\n");
        log("    - <PCF file>\n");
        log("        Path to a PCF file with IO constraints for the design\n");
        log("\n");
        log("    - <pinmap file>\n");
        log("        Path to a pinmap CSV file with package pin map\n");
        log("\n");
        log("    - <io cell specs> (optional)\n");
        log("        A space-separated list of <io cell type>:<port> or of\n");
        log("        <io cell type>:<port>:<preferred type 1>,<preferred type 2>...\n");
        log("        Each entry defines a type of IO cell to be affected an its port\n");
        log("        name that should connect to the top-level port of the design.\n");
        log("\n");
        log("        The third argument is a comma-separated list of preferred IO cell\n");
        log("        types in order of preference.\n");
        log("\n");
    }

    void execute(std::vector<std::string> a_Args, RTLIL::Design* a_Design) YS_OVERRIDE {
        if (a_Args.size() < 3) {
            log_cmd_error("    Usage: quicklogic_iob <PCF file> <pinmap file> [<io cell specs>]");
        }

        // A map of IO cell types and their port names that should go to a pad
        std::unordered_map<std::string, IoCellType> ioCellTypes;

        // Parse io cell specification
        if (a_Args.size() > 3) {

            // FIXME: Are these characters set the only ones that can be in
            // cell / port name ?
            std::regex re1("^([\\w$]+):([\\w$]+)$");
            std::regex re2("^([\\w$]+):([\\w$]+):([\\w,$]+)$");

            for (size_t i=3; i<a_Args.size(); ++i) {
                std::cmatch cm;

                // No preffered IO cell types
                if (std::regex_match(a_Args[i].c_str(), cm, re1)) {
                    ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2]));
                }

                // With preferred IO cell types
                else if (std::regex_match(a_Args[i].c_str(), cm, re2)) {
                    std::vector<std::string> preferredTypes;
                    std::stringstream ss(cm[3]);

                    while (ss.good()) {
                        std::string field;
                        std::getline(ss, field, ',');

                        preferredTypes.push_back(field);
                    }

                    ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2], preferredTypes));
                }

                // Invalid
                else {
                    log_cmd_error("Invalid IO cell+port spec: '%s'\n", a_Args[i].c_str());
                }
            }
        }

        // Use the default IO cells for QuickLogic FPGAs
        else {
            ioCellTypes.emplace("inpad",  IoCellType("inpad",  "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("outpad", IoCellType("outpad", "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("bipad",  IoCellType("bipad",  "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("ckpad",  IoCellType("ckpad",  "P", {"CLOCK", "BIDIR", "SDIOMUX"}));
        }

        // Get the top module of the design
        RTLIL::Module* topModule = a_Design->top_module();
        if (topModule == nullptr) {
            log_cmd_error("No top module detected!\n");
        }

        // Read and parse the PCF file
        log("Loading PCF from '%s'...\n", a_Args[1].c_str());
        auto pcfParser = PcfParser();
        if (!pcfParser.parse(a_Args[1])) {
            log_cmd_error("Failed to parse the PCF file!\n");
        }

        // Build a map of net names to constraints
        std::unordered_map<std::string, const PcfParser::Constraint> constraintMap;
        for (auto& constraint : pcfParser.getConstraints()) {
            if (constraintMap.count(constraint.netName) != 0) {
                log_cmd_error("The net '%s' is constrained twice!", constraint.netName.c_str());
            }
            constraintMap.emplace(constraint.netName, constraint);
        }

        // Read and parse pinmap CSV file
        log("Loading pinmap CSV from '%s'...\n", a_Args[2].c_str());
        auto pinmapParser = PinmapParser();
        if (!pinmapParser.parse(a_Args[2])) {
            log_cmd_error("Failed to parse the pinmap CSV file!\n");
        }

        // Build a map of pad names to entries
        std::unordered_map<std::string, std::vector<PinmapParser::Entry>> pinmapMap;
        for (auto& entry : pinmapParser.getEntries()) {
            if (entry.count("name") != 0) {
                auto& name = entry.at("name");

                if (pinmapMap.count(name) == 0) {
                    pinmapMap[name] = std::vector<PinmapParser::Entry>();
                }

                pinmapMap[name].push_back(entry);
            }
        }

        // Check all IO cells
        log("Processing cells...");
        log("\n");
        log("  type       | net        | pad        | loc      | type     | instance\n");
        log(" ------------+------------+------------+----------+----------+-----------\n");
        for (auto cell : topModule->cells()) {
            auto ysCellType = RTLIL::unescape_id(cell->type);

            // Not an IO cell
            if (ioCellTypes.count(ysCellType) == 0) {
                continue;
            }

            log("  %-10s ", ysCellType.c_str());

            std::string netName;
            std::string padName;
            std::string locName;
            std::string cellType;

            // Get connections to the specified port
            const auto& ioCellType = ioCellTypes.at(ysCellType);
            const std::string port = RTLIL::escape_id(ioCellType.port);
            if (cell->connections().count(port)) {

                // Get the sigspec of the connection
                auto sigspec = cell->connections().at(port);

                // Get the connected wire
                // FIXME: This assumes that the cell is directly connected to a
                // top-level port.
                if (sigspec.is_wire()) {
                    auto wire = sigspec.as_wire();

                    // Has to be top level wire
                    if (wire->port_input || wire->port_output) {

                        // Check if the wire is constrained
                        netName = RTLIL::unescape_id(wire->name);
                        if (constraintMap.count(netName)) {

                            // Get the constraint
                            auto constraint = constraintMap.at(netName);

                            // Check if there is an entry in the pinmap for this pad name
                            if (pinmapMap.count(constraint.padName)) {

                                // Choose a correct entry for the cell
                                auto entry = choosePinmapEntry(
                                    pinmapMap.at(constraint.padName),
                                    ioCellType
                                );

                                padName = constraint.padName;

                                // Location string
                                if (entry.count("x") && entry.count("y")) {
                                    locName = stringf("X%sY%s",
                                        entry.at("x").c_str(),
                                        entry.at("y").c_str()
                                    );
                                }

                                // Cell type
                                if (entry.count("type")) {
                                    cellType = entry.at("type");
                                }
                            }
                        }
                    }
                }
            }

            log("| %-10s | %-10s | %-8s | %-8s | %s\n",
                netName.c_str(),
                padName.c_str(),
                locName.c_str(),
                cellType.c_str(),
                cell->name.c_str()
            );

            // Annotate the cell by setting its parameters
            cell->setParam(RTLIL::escape_id("IO_PAD"),  padName);
            cell->setParam(RTLIL::escape_id("IO_LOC"),  locName);
            cell->setParam(RTLIL::escape_id("IO_TYPE"), cellType);
        }
    }

    PinmapParser::Entry choosePinmapEntry(
        const std::vector<PinmapParser::Entry>& a_Entries,
        const IoCellType& a_IoCellType)
    {
        // No preferred types, pick the first one
        if (a_IoCellType.preferredTypes.empty()) {
            return a_Entries[0];
        }

        // Loop over preferred types
        for (auto& type : a_IoCellType.preferredTypes) {

            // Find an entry for that type. If found then return it.
            for (auto& entry : a_Entries) {
                if (type == entry.at("type")) {
                    return entry;
                }
            }
        }

        // No preferred type was found, pick the first one.
        return a_Entries[0];
    }

} QuicklogicIob;

PRIVATE_NAMESPACE_END
<commit_msg>Fixed the ql-iob plugin to work with multi-bit nets<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *  Copyright (C) 2020  The Symbiflow Authors
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "pcf_parser.hh"
#include "pinmap_parser.hh"

#include "kernel/register.h"
#include "kernel/rtlil.h"

#include <regex>
#include <sstream>

#ifndef YOSYS_OVERRIDE
#define YOSYS_OVERRIDE override
#endif

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

void register_in_tcl_interpreter(const std::string& command) {
    Tcl_Interp* interp = yosys_get_tcl_interp();
    std::string tcl_script = stringf("proc %s args { return [yosys %s {*}$args] }", command.c_str(), command.c_str());
    Tcl_Eval(interp, tcl_script.c_str());
}

struct QuicklogicIob : public Pass {

    struct IoCellType {
        std::string type;                        // Cell type
        std::string port;                        // Name of the port that goes to a pad
        std::vector<std::string> preferredTypes; // A list of preferred IO cell types

        IoCellType (const std::string& _type, const std::string& _port, const std::vector<std::string> _preferredTypes = std::vector<std::string>()) :
            type(_type),
            port(_port),
            preferredTypes(_preferredTypes)
        {}
    };

    QuicklogicIob () :
        Pass("quicklogic_iob", "Map IO buffers to cells that correspond to their assigned locations") {
            register_in_tcl_interpreter(pass_name);
        }

    void help() YS_OVERRIDE {
        log("\n");
        log("    quicklogic_iob <PCF file> <pinmap file> [<io cell specs>]");
        log("\n");
        log("This command assigns certain parameters of the specified IO cell types\n");
        log("basing on the placement constraints and the pin map of the target device\n");
        log("\n");
        log("Each affected IO cell is assigned the followin parameters:\n");
        log(" - IO_PAD  = \"<IO pad name>\"\n");
        log(" - IO_LOC  = \"<IO cell location>\"\n");
        log(" - IO_CELL = \"<IO cell type>\"\n");
        log("\n");
        log("Parameters:\n");
        log("\n");
        log("    - <PCF file>\n");
        log("        Path to a PCF file with IO constraints for the design\n");
        log("\n");
        log("    - <pinmap file>\n");
        log("        Path to a pinmap CSV file with package pin map\n");
        log("\n");
        log("    - <io cell specs> (optional)\n");
        log("        A space-separated list of <io cell type>:<port> or of\n");
        log("        <io cell type>:<port>:<preferred type 1>,<preferred type 2>...\n");
        log("        Each entry defines a type of IO cell to be affected an its port\n");
        log("        name that should connect to the top-level port of the design.\n");
        log("\n");
        log("        The third argument is a comma-separated list of preferred IO cell\n");
        log("        types in order of preference.\n");
        log("\n");
    }

    void execute(std::vector<std::string> a_Args, RTLIL::Design* a_Design) YS_OVERRIDE {
        if (a_Args.size() < 3) {
            log_cmd_error("    Usage: quicklogic_iob <PCF file> <pinmap file> [<io cell specs>]");
        }

        // A map of IO cell types and their port names that should go to a pad
        std::unordered_map<std::string, IoCellType> ioCellTypes;

        // Parse io cell specification
        if (a_Args.size() > 3) {

            // FIXME: Are these characters set the only ones that can be in
            // cell / port name ?
            std::regex re1("^([\\w$]+):([\\w$]+)$");
            std::regex re2("^([\\w$]+):([\\w$]+):([\\w,$]+)$");

            for (size_t i=3; i<a_Args.size(); ++i) {
                std::cmatch cm;

                // No preffered IO cell types
                if (std::regex_match(a_Args[i].c_str(), cm, re1)) {
                    ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2]));
                }

                // With preferred IO cell types
                else if (std::regex_match(a_Args[i].c_str(), cm, re2)) {
                    std::vector<std::string> preferredTypes;
                    std::stringstream ss(cm[3]);

                    while (ss.good()) {
                        std::string field;
                        std::getline(ss, field, ',');

                        preferredTypes.push_back(field);
                    }

                    ioCellTypes.emplace(cm[1].str(), IoCellType(cm[1], cm[2], preferredTypes));
                }

                // Invalid
                else {
                    log_cmd_error("Invalid IO cell+port spec: '%s'\n", a_Args[i].c_str());
                }
            }
        }

        // Use the default IO cells for QuickLogic FPGAs
        else {
            ioCellTypes.emplace("inpad",  IoCellType("inpad",  "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("outpad", IoCellType("outpad", "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("bipad",  IoCellType("bipad",  "P", {"BIDIR", "SDIOMUX"}));
            ioCellTypes.emplace("ckpad",  IoCellType("ckpad",  "P", {"CLOCK", "BIDIR", "SDIOMUX"}));
        }

        // Get the top module of the design
        RTLIL::Module* topModule = a_Design->top_module();
        if (topModule == nullptr) {
            log_cmd_error("No top module detected!\n");
        }

        // Read and parse the PCF file
        log("Loading PCF from '%s'...\n", a_Args[1].c_str());
        auto pcfParser = PcfParser();
        if (!pcfParser.parse(a_Args[1])) {
            log_cmd_error("Failed to parse the PCF file!\n");
        }

        // Build a map of net names to constraints
        std::unordered_map<std::string, const PcfParser::Constraint> constraintMap;
        for (auto& constraint : pcfParser.getConstraints()) {
            if (constraintMap.count(constraint.netName) != 0) {
                log_cmd_error("The net '%s' is constrained twice!", constraint.netName.c_str());
            }
            constraintMap.emplace(constraint.netName, constraint);
        }

        // Read and parse pinmap CSV file
        log("Loading pinmap CSV from '%s'...\n", a_Args[2].c_str());
        auto pinmapParser = PinmapParser();
        if (!pinmapParser.parse(a_Args[2])) {
            log_cmd_error("Failed to parse the pinmap CSV file!\n");
        }

        // Build a map of pad names to entries
        std::unordered_map<std::string, std::vector<PinmapParser::Entry>> pinmapMap;
        for (auto& entry : pinmapParser.getEntries()) {
            if (entry.count("name") != 0) {
                auto& name = entry.at("name");

                if (pinmapMap.count(name) == 0) {
                    pinmapMap[name] = std::vector<PinmapParser::Entry>();
                }

                pinmapMap[name].push_back(entry);
            }
        }

        // Check all IO cells
        log("Processing cells...");
        log("\n");
        log("  type       | net        | pad        | loc      | type     | instance\n");
        log(" ------------+------------+------------+----------+----------+-----------\n");
        for (auto cell : topModule->cells()) {
            auto ysCellType = RTLIL::unescape_id(cell->type);

            // Not an IO cell
            if (ioCellTypes.count(ysCellType) == 0) {
                continue;
            }

            log("  %-10s ", ysCellType.c_str());

            std::string netName;
            std::string padName;
            std::string locName;
            std::string cellType;

            // Get connections to the specified port
            const auto& ioCellType = ioCellTypes.at(ysCellType);
            const std::string port = RTLIL::escape_id(ioCellType.port);
            if (cell->connections().count(port)) {

                // Get the sigspec of the connection
                auto sigspec = cell->connections().at(port);

                // Get the connected wire
                for (auto sigbit : sigspec.bits()) {
                    if (sigbit.wire != nullptr) {
                        auto wire = sigbit.wire;

                        // Has to be top level wire
                        if (wire->port_input || wire->port_output) {

                            // Check if the wire is constrained. Get pad name.
                            std::string baseName = RTLIL::unescape_id(wire->name);
                            std::string netNames[] = {
                                baseName,
                                stringf("%s[%d]", baseName.c_str(), sigbit.offset),
                                stringf("%s(%d)", baseName.c_str(), sigbit.offset),
                            };

                            padName = "";
                            netName = "";

                            for (auto& name : netNames) {
                                if (constraintMap.count(name)) {
                                    auto constraint = constraintMap.at(name);
                                    padName = constraint.padName;
                                    netName = name;
                                    break;
                                }
                            }

                            // Check if there is an entry in the pinmap for this pad name
                            if (pinmapMap.count(padName)) {

                                // Choose a correct entry for the cell
                                auto entry = choosePinmapEntry(
                                    pinmapMap.at(padName),
                                    ioCellType
                                );

                                // Location string
                                if (entry.count("x") && entry.count("y")) {
                                    locName = stringf("X%sY%s",
                                        entry.at("x").c_str(),
                                        entry.at("y").c_str()
                                    );
                                }

                                // Cell type
                                if (entry.count("type")) {
                                    cellType = entry.at("type");
                                }
                            }
                        }
                    }
                }
            }

            log("| %-10s | %-10s | %-8s | %-8s | %s\n",
                netName.c_str(),
                padName.c_str(),
                locName.c_str(),
                cellType.c_str(),
                cell->name.c_str()
            );

            // Annotate the cell by setting its parameters
            cell->setParam(RTLIL::escape_id("IO_PAD"),  padName);
            cell->setParam(RTLIL::escape_id("IO_LOC"),  locName);
            cell->setParam(RTLIL::escape_id("IO_TYPE"), cellType);
        }
    }

    PinmapParser::Entry choosePinmapEntry(
        const std::vector<PinmapParser::Entry>& a_Entries,
        const IoCellType& a_IoCellType)
    {
        // No preferred types, pick the first one
        if (a_IoCellType.preferredTypes.empty()) {
            return a_Entries[0];
        }

        // Loop over preferred types
        for (auto& type : a_IoCellType.preferredTypes) {

            // Find an entry for that type. If found then return it.
            for (auto& entry : a_Entries) {
                if (type == entry.at("type")) {
                    return entry;
                }
            }
        }

        // No preferred type was found, pick the first one.
        return a_Entries[0];
    }

} QuicklogicIob;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/***************************************************************************
 *  stream/test_loop.cpp
 *
 *  (optional) short description
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2011 Jaroslaw Fedorowics <fedorow@cs.uni-frankfurt.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

//! \example stream/test_loop.cpp
//! This is an example of how to use some basic algorithms from the
//! stream package to form a loop iterating over the data.
//! Some input is generated, sorted, some elements are filtered out.
//! The remaining elements are transformed, sorted and processed in the
//! next pass. The loop will terminate if at most one element remains.
//! A split sorter is used to cut the data flow (and type dependency) cycle.

#include <iostream>

#include <stxxl/io>
#include <stxxl/vector>
#include <stxxl/stream>

using std::cout;
using std::endl;

const stxxl::uint64 memory_to_use = 3ul * 1024 * 1024 * 1024;

bool verbose;

struct random_generator {
    typedef stxxl::random_number32::value_type value_type;
    value_type current;
    int count;
    stxxl::random_number32 rnd;

    random_generator(int _count) : count(_count)
    {
        if (verbose) cout << "Random Stream: ";
        current = rnd();
    }

    value_type operator * () const
    {
        return current;
    }
    random_generator & operator ++ ()
    {
        count--;
        if (verbose) {
            cout << current << ", ";
            if (empty()) cout << endl;
        }
        current = rnd();
        return *this;
    }
    bool empty() const
    {
        return (count == 0);
    }
};

template <typename value_type>
struct Cmp {
    bool operator () (const value_type & a, const value_type & b) const
    {
        return a < b;
    }
    static value_type min_value()
    {
        return value_type((std::numeric_limits<value_type>::min)());
    }
    static value_type max_value()
    {
        return value_type((std::numeric_limits<value_type>::max)());
    }
};

template <typename Input>
struct filter {
    typedef typename Input::value_type value_type;
    Input & input;
    value_type filter_value;
    int & counter;

    void apply_filter()
    {
        while (!input.empty() && *input == filter_value) {
            ++input;
            counter++;
        }
    }

    filter(Input & _input, value_type _filter_value, int & _counter) : input(_input), filter_value(_filter_value), counter(_counter)
    {
        apply_filter();
    }

    const value_type operator * () const
    {
        return *input;
    }

    filter & operator ++ ()
    {
        ++input;
        apply_filter();
        return *this;
    }

    bool empty() const
    {
        return input.empty();
    }
};

template <typename Input>
struct output {
    typedef typename Input::value_type value_type;
    Input & input;

    output(Input & _input) : input(_input) { }

    const value_type operator * () const
    {
        return *input;
    }

    output & operator ++ ()
    {
        if (verbose) cout << *input << ", ";
        ++input;
        if (empty() && verbose)
            cout << endl;
        return *this;
    }

    bool empty() const
    {
        return input.empty();
    }
};

template <typename Input>
struct shuffle {
    typedef typename Input::value_type value_type;
    Input & input;
    value_type current, next;
    bool even, is_empty;

    // from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
    int count_bits(unsigned long v)
    {
        int c;
        for (c = 0; v; c++) {
            v &= v - 1;
        }
        return c;
    }

    void apply_shuffle()
    {
        is_empty = input.empty();
        if (!is_empty) {
            current = *input;
            ++input;
            if (!input.empty()) {
                unsigned long combined = current;
                combined = combined << 32 | *input;
                combined = (1ul << count_bits(combined)) - 1;
                current = combined >> 32;
                next = combined;
            }
        }
    }

    shuffle(Input & _input) : input(_input), current(0), next(0), even(true), is_empty(false)
    {
        apply_shuffle();
    }

    value_type operator * () const
    {
        return current;
    }

    shuffle & operator ++ ()
    {
        even = !even;
        is_empty = input.empty();
        if (even) {
            ++input;
            apply_shuffle();
        } else {
            current = next;
        }
        return *this;
    }

    bool empty() const
    {
        return is_empty;
    }
};

typedef random_generator random_generator_type;
typedef Cmp<random_generator_type::value_type> cmp;
typedef stxxl::stream::runs_creator<random_generator_type, cmp> runs_creator_type0;
typedef runs_creator_type0::sorted_runs_type sorted_runs_type;
typedef stxxl::stream::runs_merger<sorted_runs_type, cmp> runs_merger_type;
typedef output<runs_merger_type> output_type;
typedef filter<output_type> filter_type0;
typedef filter<filter_type0> filter_type1;
typedef shuffle<filter_type1> shuffle_type;
typedef stxxl::stream::runs_creator<shuffle_type, cmp> runs_creator_type1;

int main(int argc, char ** argv)
{
    if (argc < 2) {
        cout << "Usage: " << argv[0] << " count [Options]\nOptions: -v \t prints elements of each iteration\n";
        return EXIT_FAILURE;
    }

    stxxl::block_manager::get_instance();

    verbose = (argc == 3) && !strcmp(argv[2], "-v");

    int total = atoi(argv[1]);

    random_generator random_stream(total);

    runs_creator_type0 runs_creator(random_stream, cmp(), memory_to_use);

    sorted_runs_type sorted_runs = runs_creator.result();

    int counter = 0;
    int i;

    for (i = 0; counter < total - 1; ++i) {
        if (verbose) cout << "Iteration " << i << ": ";

        runs_merger_type runs_merger(sorted_runs, cmp(), memory_to_use);

        output_type output_stream(runs_merger);

        filter_type0 filter0(output_stream, 0, counter);

        filter_type1 filter1(filter0, -1, counter);

        shuffle_type shuffled_stream(filter1);

        runs_creator_type1 runs_creator(shuffled_stream, cmp(), memory_to_use);

        sorted_runs = runs_creator.result();
    }

    runs_merger_type runs_merger(sorted_runs, cmp(), memory_to_use);

    while (!runs_merger.empty()) {
        if (verbose) cout << "Iteration " << i << ": " << *runs_merger << endl;
        ++runs_merger;
    }
    cout << "\nIteration needed: " << i << endl;
}

// vim: et:ts=4:sw=4
<commit_msg>fixup types<commit_after>/***************************************************************************
 *  stream/test_loop.cpp
 *
 *  (optional) short description
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2011 Jaroslaw Fedorowics <fedorow@cs.uni-frankfurt.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

//! \example stream/test_loop.cpp
//! This is an example of how to use some basic algorithms from the
//! stream package to form a loop iterating over the data.
//! Some input is generated, sorted, some elements are filtered out.
//! The remaining elements are transformed, sorted and processed in the
//! next pass. The loop will terminate if at most one element remains.
//! A split sorter is used to cut the data flow (and type dependency) cycle.

#include <iostream>

#include <stxxl/io>
#include <stxxl/vector>
#include <stxxl/stream>

using std::cout;
using std::endl;

const stxxl::uint64 memory_to_use = 3ul * 1024 * 1024 * 1024;

bool verbose;

struct random_generator {
    typedef stxxl::random_number32::value_type value_type;
    value_type current;
    int count;
    stxxl::random_number32 rnd;

    random_generator(int _count) : count(_count)
    {
        if (verbose) cout << "Random Stream: ";
        current = rnd();
    }

    value_type operator * () const
    {
        return current;
    }
    random_generator & operator ++ ()
    {
        count--;
        if (verbose) {
            cout << current << ", ";
            if (empty()) cout << endl;
        }
        current = rnd();
        return *this;
    }
    bool empty() const
    {
        return (count == 0);
    }
};

template <typename value_type>
struct Cmp {
    bool operator () (const value_type & a, const value_type & b) const
    {
        return a < b;
    }
    static value_type min_value()
    {
        return value_type((std::numeric_limits<value_type>::min)());
    }
    static value_type max_value()
    {
        return value_type((std::numeric_limits<value_type>::max)());
    }
};

template <typename Input>
struct filter {
    typedef typename Input::value_type value_type;
    Input & input;
    value_type filter_value;
    int & counter;

    void apply_filter()
    {
        while (!input.empty() && *input == filter_value) {
            ++input;
            counter++;
        }
    }

    filter(Input & _input, value_type _filter_value, int & _counter) : input(_input), filter_value(_filter_value), counter(_counter)
    {
        apply_filter();
    }

    const value_type operator * () const
    {
        return *input;
    }

    filter & operator ++ ()
    {
        ++input;
        apply_filter();
        return *this;
    }

    bool empty() const
    {
        return input.empty();
    }
};

template <typename Input>
struct output {
    typedef typename Input::value_type value_type;
    Input & input;

    output(Input & _input) : input(_input) { }

    const value_type operator * () const
    {
        return *input;
    }

    output & operator ++ ()
    {
        if (verbose) cout << *input << ", ";
        ++input;
        if (empty() && verbose)
            cout << endl;
        return *this;
    }

    bool empty() const
    {
        return input.empty();
    }
};

template <typename Input>
struct shuffle {
    typedef typename Input::value_type value_type;
    Input & input;
    value_type current, next;
    bool even, is_empty;

    // from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
    int count_bits(unsigned long v)
    {
        int c;
        for (c = 0; v; c++) {
            v &= v - 1;
        }
        return c;
    }

    void apply_shuffle()
    {
        is_empty = input.empty();
        if (!is_empty) {
            current = *input;
            ++input;
            if (!input.empty()) {
                STXXL_STATIC_ASSERT(sizeof(value_type) == 4);
                stxxl::uint64 combined = current;
                combined = combined << 32 | *input;
                combined = (1ul << count_bits(combined)) - 1;
                current = combined >> 32;
                next = combined;
            }
        }
    }

    shuffle(Input & _input) : input(_input), current(0), next(0), even(true), is_empty(false)
    {
        apply_shuffle();
    }

    value_type operator * () const
    {
        return current;
    }

    shuffle & operator ++ ()
    {
        even = !even;
        is_empty = input.empty();
        if (even) {
            ++input;
            apply_shuffle();
        } else {
            current = next;
        }
        return *this;
    }

    bool empty() const
    {
        return is_empty;
    }
};

typedef random_generator input_generator_type;
typedef Cmp<input_generator_type::value_type> cmp;
typedef stxxl::stream::runs_creator<input_generator_type, cmp> runs_creator_type0;
typedef runs_creator_type0::sorted_runs_type sorted_runs_type;
typedef stxxl::stream::runs_merger<sorted_runs_type, cmp> runs_merger_type;
typedef output<runs_merger_type> output_type;
typedef filter<output_type> filter_type0;
typedef filter<filter_type0> filter_type1;
typedef shuffle<filter_type1> shuffle_type;
typedef stxxl::stream::runs_creator<shuffle_type, cmp> runs_creator_type1;

int main(int argc, char ** argv)
{
    if (argc < 2) {
        cout << "Usage: " << argv[0] << " count [Options]\nOptions: -v \t prints elements of each iteration\n";
        return EXIT_FAILURE;
    }

    stxxl::block_manager::get_instance();

    verbose = (argc == 3) && !strcmp(argv[2], "-v");

    int total = atoi(argv[1]);

    input_generator_type input_stream(total);

    runs_creator_type0 runs_creator(input_stream, cmp(), memory_to_use);

    sorted_runs_type sorted_runs = runs_creator.result();

    int counter = 0;
    int i;

    for (i = 0; counter < total - 1; ++i) {
        if (verbose) cout << "Iteration " << i << ": ";

        runs_merger_type runs_merger(sorted_runs, cmp(), memory_to_use);

        output_type output_stream(runs_merger);

        filter_type0 filter0(output_stream, 0, counter);

        filter_type1 filter1(filter0, -1, counter);

        shuffle_type shuffled_stream(filter1);

        runs_creator_type1 runs_creator(shuffled_stream, cmp(), memory_to_use);

        sorted_runs = runs_creator.result();
    }

    runs_merger_type runs_merger(sorted_runs, cmp(), memory_to_use);

    while (!runs_merger.empty()) {
        if (verbose) cout << "Iteration " << i << ": " << *runs_merger << endl;
        ++runs_merger;
    }
    cout << "\nIteration needed: " << i << endl;
}

// vim: et:ts=4:sw=4
<|endoftext|>