<commit_before>#include "Players/Genetic_AI.h"

#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <stdexcept>

#include "Moves/Complete_Move.h"
#include "Game/Board.h"
#include "Game/Clock.h"
#include "Game/Game_Result.h"
#include "Players/Thinking.h"

#include "Utility.h"

int Genetic_AI::next_id = 0;

Genetic_AI::Genetic_AI() :
    genome(),
    id(next_id++)
{
}

// Sexual reproduction
Genetic_AI::Genetic_AI(const Genetic_AI& A, const Genetic_AI& B) :
    genome(A.genome, B.genome),
    id(next_id++)
{
}

Genetic_AI::Genetic_AI(const std::string& file_name)
{
    std::ifstream ifs(file_name);
    if( ! ifs)
    {
        throw std::runtime_error("Could not read: " + file_name);
    }

    read_from(ifs);
}

Genetic_AI::Genetic_AI(std::istream& is)
{
    read_from(is);
}

Genetic_AI::Genetic_AI(const std::string& file_name, int id_in) : id(id_in)
{
    if(id >= next_id)
    {
        next_id = id + 1;
    }

    std::ifstream ifs(file_name);
    if( ! ifs)
    {
        throw std::runtime_error("Could not read: " + file_name);
    }

    std::string line;
    while(std::getline(ifs, line))
    {
        if( ! String::starts_with(line, "ID:"))
        {
            continue;
        }

        auto param_value = String::split(line, ":", 1);
        if(id_in == std::stoi(param_value[1]))
        {
            genome.read_from(ifs);
            return;
        }
    }

    throw std::runtime_error("Could not locate ID " + std::to_string(id_in) + " inside file " + file_name);
}

void Genetic_AI::read_from(std::istream& is)
{
    std::string line;
    id = -1;
    while(std::getline(is, line))
    {
        if(line.empty())
        {
            continue;
        }

        if(String::starts_with(line, "ID:"))
        {
            id = std::stoi(String::split(line)[1]);
            break;
        }
        else
        {
            throw std::runtime_error("Invalid Genetic_AI line: " + line);
        }
    }

    if( ! is)
    {
        throw std::runtime_error("Incomplete Genetic_AI spec in file for ID " + std::to_string(id));
    }

    if(id >= next_id)
    {
        next_id = id + 1;
    }

    genome.read_from(is);
}

const Complete_Move Genetic_AI::choose_move(const Board& board, const Clock& clock) const
{
    nodes_searched = 0;
    clock_start_time = clock.time_left(clock.running_for());

    const auto& legal_moves = board.legal_moves();
    if(legal_moves.size() == 1)
    {
        if(principal_variation.size() > 2 && principal_variation[1] == board.get_game_record().back())
        {
            // search_game_tree() assumes the principal variation starts
            // with the previous move of this player. If a move was forced,
            // then the principal variation needs to be updated to start with
            // the next move of this side after checking that the immediately
            // preceding move was the expected one.
            principal_variation.erase(principal_variation.begin(),
                                      principal_variation.begin() + 2);
        }
        else
        {
            principal_variation.clear();
        }

        commentary.push_back(principal_variation);

        return legal_moves.front(); // If there's only one legal move, take it.
    }

    auto time_to_use = genome.time_to_examine(board, clock);

    // alpha = highest score found that opponent will allow
    Game_Tree_Node_Result alpha_start = {Complete_Move(),
                                         Math::lose_score,
                                         board.whose_turn(),
                                         0,
                                         {}};

    // beta = score that will cause opponent to choose a different prior move
    Game_Tree_Node_Result beta_start = {Complete_Move(),
                                        Math::win_score,
                                        board.whose_turn(),
                                        0,
                                        {}};

    auto result = search_game_tree(board,
                                   time_to_use,
                                   clock,
                                   0,
                                   alpha_start,
                                   beta_start);

    if(board.get_thinking_mode() == CECP)
    {
        output_thinking_cecp(result, clock, board.whose_turn());
        std::cout << std::flush;
    }

    if(result.depth > 0)
    {
        principal_variation = result.commentary;
    }
    else
    {
        principal_variation.clear();
    }
    commentary.push_back(principal_variation);

    return result.move;
}

bool better_than(const Game_Tree_Node_Result& a, const Game_Tree_Node_Result& b, Color perspective)
{
    auto scoreA = a.corrected_score(perspective);
    auto scoreB = b.corrected_score(perspective);

    if(scoreA > scoreB)
    {
        return true;
    }

    if(scoreA < scoreB)
    {
        return false;
    }

    // scoreA == scoreB

    // Shorter path to winning is better
    if(scoreA == Math::win_score)
    {
        return a.depth < b.depth;
    }

    // Longer path to losing is better
    if(scoreA == Math::lose_score)
    {
        return a.depth > b.depth;
    }

    return false;
}

bool operator==(const Game_Tree_Node_Result& a, const Game_Tree_Node_Result& b)
{
    auto scoreA = a.corrected_score(WHITE);
    auto scoreB = b.corrected_score(WHITE);

    if(scoreA != scoreB)
    {
        return false;
    }

    // scoreA == scoreB

    if(std::abs(scoreA) == Math::win_score)
    {
        return a.depth == b.depth;
    }

    return true;
}

Game_Tree_Node_Result Genetic_AI::search_game_tree(const Board& board,
                                                   const double time_to_examine,
                                                   const Clock& clock,
                                                   const size_t depth,
                                                   Game_Tree_Node_Result alpha,
                                                   Game_Tree_Node_Result beta) const
{
    auto time_start = clock.time_left(clock.running_for());
    auto all_legal_moves = board.legal_moves();

    // The first item in the principal variation is the last move that
    // this player made. Since then, the opponent has also made a move,
    // so the first item in the principal variation corresponds to the
    // game record item at game_record.size() - 2. The depth of the game
    // tree search increments both the game_record index and the principal
    // variation index in step.
    bool still_on_principal_variation = false;
    if(principal_variation.size() > depth + 2)
    {
        still_on_principal_variation = std::equal(board.get_game_record().end() - 2 - depth,
                                                  board.get_game_record().end(),
                                                  principal_variation.begin());

        if(still_on_principal_variation)
        {
            auto next_principal_variation_move = board.get_complete_move(principal_variation[depth + 2]);
            auto move_iter = std::find(all_legal_moves.begin(),
                                       all_legal_moves.end(),
                                       next_principal_variation_move);

            // Make sure that the principal variation is actually a legal move.
            // This is purely for debugging as special circumstances (i.e., once
            // per several thousand games) cause the principal variation to be
            // invalidated without it being cleared.
            if(move_iter == all_legal_moves.end())
            {
                board.ascii_draw(WHITE);
                board.print_game_record(nullptr,
                                        nullptr,
                                        "",
                                        Game_Result(NONE, "Principal Variation error", false),
                                        0, 0, 0,
                                        Clock());
                auto board_copy = board;
                for(const auto& item : principal_variation)
                {
                    auto move = board_copy.get_complete_move(item);
                    std::cout << move.game_record_item(board_copy) << " ";
                    board_copy.submit_move(move);
                }
                std::cout << '\n' << "Depth: " << depth << '\n'
                          << "Next move in variation: "
                          << next_principal_variation_move.game_record_item(board)
                          << std::endl;
                throw std::runtime_error("ERROR: bad variation code");
            }

            // Put principal variation move at start of list to allow
            // the most pruning later.
            std::iter_swap(all_legal_moves.begin(), move_iter);
        }
    }

    auto perspective = board.whose_turn();
    int moves_examined = 0;
    const auto current_legal_moves_count = all_legal_moves.size();

    Game_Tree_Node_Result best_result = {board.legal_moves().front(),
                                         Math::lose_score,
                                         perspective,
                                         depth,
                                         {}};

    for(const auto& move : all_legal_moves)
    {
        ++nodes_searched;

        auto next_board = board;

        auto move_result = next_board.submit_move(move);
        if(move_result.get_winner() != NONE)
        {
            // Mate in one (try to pick the shortest path to checkmate)
            return {move,
                    genome.evaluate(next_board, move_result, perspective),
                    perspective,
                    depth,
                    {next_board.get_game_record().end() - (depth + 1),
                     next_board.get_game_record().end()}};
        }

        if(alpha.depth <= depth + 2 && alpha.corrected_score(perspective) == Math::win_score)
        {
            // This move will take a longer path to victory
            // than one already found. Use "depth + 2" since,
            // if this move isn't winning (and it isn't, since
            // we're here), then the earliest move that can
            // win is the next one, which is two away (after
            // opponent's move).
            continue;
        }

        int moves_left = current_legal_moves_count - moves_examined;
        double time_left = time_to_examine - (time_start - clock.time_left(clock.running_for()));
        double time_allotted_for_this_move = time_left/moves_left;

        bool recurse;
        if(move_result.game_has_ended())
        {
            recurse = false;
        }
        else if(next_board.legal_moves().size() == 1)
        {
            recurse = true;
        }
        else if(still_on_principal_variation)
        {
            recurse = true;
        }
        else
        {
            recurse = genome.enough_time_to_recurse(time_allotted_for_this_move, next_board);
        }

        Game_Tree_Node_Result result;
        if(recurse)
        {
            result = search_game_tree(next_board,
                                      time_allotted_for_this_move,
                                      clock,
                                      depth + 1,
                                      beta,
                                      alpha);

            // Update last result with this game tree node's data
            result.move = move;
        }
        else
        {
            // Record immediate result without looking ahead further
            result = {move,
                      genome.evaluate(next_board, move_result, perspective),
                      perspective,
                      depth,
                      {next_board.get_game_record().end() - (depth + 1),
                       next_board.get_game_record().end()}};
        }

        if(better_than(result, best_result, perspective))
        {
            best_result = result;
            if(better_than(best_result, alpha, perspective))
            {
                alpha = best_result;
                if(better_than(alpha, beta, perspective) || alpha == beta)
                {
                    break;
                }
                else if(depth % 2 == 0 && board.get_thinking_mode() == CECP)
                {
                    output_thinking_cecp(alpha, clock, perspective);
                }
            }
        }

        ++moves_examined;
        still_on_principal_variation = false; // only the first move is part of the principal variation

        if(clock.time_left(clock.running_for()) < 0)
        {
            break;
        }
    }

    return best_result;
}

void Genetic_AI::mutate()
{
    genome.mutate();
}

void Genetic_AI::print_genome(const std::string& file_name) const
{
    if(file_name.empty())
    {
        print_genome(std::cout);
    }
    else
    {
        auto dest = std::ofstream(file_name, std::ofstream::app);
        print_genome(dest);
    }
}

void Genetic_AI::print_genome(std::ostream& os) const
{
    os << "ID: " << get_id() << std::endl;
    genome.print(os);
    os << "END" << std::endl << std::endl;
}

std::string Genetic_AI::name() const
{
    return "Genetic AI " + std::to_string(get_id());
}

std::string Genetic_AI::author() const
{
    return "Mark Harrison";
}

int Genetic_AI::get_id() const
{
    return id;
}

bool Genetic_AI::operator<(const Genetic_AI& other) const
{
    return get_id() < other.get_id();
}

bool Genetic_AI::operator==(const Genetic_AI& other) const
{
    return get_id() == other.get_id();
}

std::string Genetic_AI::get_commentary_for_move(size_t move_number) const
{
    std::string result;
    if(move_number < commentary.size() && ! commentary.at(move_number).empty())
    {
        result = commentary.at(move_number).front();
        for(size_t i = 1; i < commentary.at(move_number).size(); ++i)
        {
            result += " " + commentary.at(move_number).at(i);
        }
    }

    return result;
}

void Genetic_AI::output_thinking_cecp(const Game_Tree_Node_Result& thought,
                                      const Clock& clock,
                                      Color perspective) const
{
    auto score = thought.corrected_score(perspective);
    if(score == Math::win_score)
    {
        score = 10000 - thought.depth;
    }
    else if(score == Math::lose_score)
    {
        score = -(10000 - thought.depth);
    }

    std::cout << thought.depth // ply
              << " "
              << int(score) // score in what should be centipawns
              << " "
              << int((clock_start_time - clock.time_left(clock.running_for()))*100) // search time in centiseconds
              << " "
              << nodes_searched; // number of nodes searched

    // Principal variation
    for(const auto& move : thought.commentary)
    {
        std::cout << " " << move;
    }

    std::cout << '\n';
}
<commit_msg>Fix mate-in-N-moves output<commit_after>#include "Players/Genetic_AI.h"

#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <stdexcept>

#include "Moves/Complete_Move.h"
#include "Game/Board.h"
#include "Game/Clock.h"
#include "Game/Game_Result.h"
#include "Players/Thinking.h"

#include "Utility.h"

int Genetic_AI::next_id = 0;

Genetic_AI::Genetic_AI() :
    genome(),
    id(next_id++)
{
}

// Sexual reproduction
Genetic_AI::Genetic_AI(const Genetic_AI& A, const Genetic_AI& B) :
    genome(A.genome, B.genome),
    id(next_id++)
{
}

Genetic_AI::Genetic_AI(const std::string& file_name)
{
    std::ifstream ifs(file_name);
    if( ! ifs)
    {
        throw std::runtime_error("Could not read: " + file_name);
    }

    read_from(ifs);
}

Genetic_AI::Genetic_AI(std::istream& is)
{
    read_from(is);
}

Genetic_AI::Genetic_AI(const std::string& file_name, int id_in) : id(id_in)
{
    if(id >= next_id)
    {
        next_id = id + 1;
    }

    std::ifstream ifs(file_name);
    if( ! ifs)
    {
        throw std::runtime_error("Could not read: " + file_name);
    }

    std::string line;
    while(std::getline(ifs, line))
    {
        if( ! String::starts_with(line, "ID:"))
        {
            continue;
        }

        auto param_value = String::split(line, ":", 1);
        if(id_in == std::stoi(param_value[1]))
        {
            genome.read_from(ifs);
            return;
        }
    }

    throw std::runtime_error("Could not locate ID " + std::to_string(id_in) + " inside file " + file_name);
}

void Genetic_AI::read_from(std::istream& is)
{
    std::string line;
    id = -1;
    while(std::getline(is, line))
    {
        if(line.empty())
        {
            continue;
        }

        if(String::starts_with(line, "ID:"))
        {
            id = std::stoi(String::split(line)[1]);
            break;
        }
        else
        {
            throw std::runtime_error("Invalid Genetic_AI line: " + line);
        }
    }

    if( ! is)
    {
        throw std::runtime_error("Incomplete Genetic_AI spec in file for ID " + std::to_string(id));
    }

    if(id >= next_id)
    {
        next_id = id + 1;
    }

    genome.read_from(is);
}

const Complete_Move Genetic_AI::choose_move(const Board& board, const Clock& clock) const
{
    nodes_searched = 0;
    clock_start_time = clock.time_left(clock.running_for());

    const auto& legal_moves = board.legal_moves();
    if(legal_moves.size() == 1)
    {
        if(principal_variation.size() > 2 && principal_variation[1] == board.get_game_record().back())
        {
            // search_game_tree() assumes the principal variation starts
            // with the previous move of this player. If a move was forced,
            // then the principal variation needs to be updated to start with
            // the next move of this side after checking that the immediately
            // preceding move was the expected one.
            principal_variation.erase(principal_variation.begin(),
                                      principal_variation.begin() + 2);
        }
        else
        {
            principal_variation.clear();
        }

        commentary.push_back(principal_variation);

        return legal_moves.front(); // If there's only one legal move, take it.
    }

    auto time_to_use = genome.time_to_examine(board, clock);

    // alpha = highest score found that opponent will allow
    Game_Tree_Node_Result alpha_start = {Complete_Move(),
                                         Math::lose_score,
                                         board.whose_turn(),
                                         0,
                                         {}};

    // beta = score that will cause opponent to choose a different prior move
    Game_Tree_Node_Result beta_start = {Complete_Move(),
                                        Math::win_score,
                                        board.whose_turn(),
                                        0,
                                        {}};

    auto result = search_game_tree(board,
                                   time_to_use,
                                   clock,
                                   0,
                                   alpha_start,
                                   beta_start);

    if(board.get_thinking_mode() == CECP)
    {
        output_thinking_cecp(result, clock, board.whose_turn());
        std::cout << std::flush;
    }

    if(result.depth > 0)
    {
        principal_variation = result.commentary;
    }
    else
    {
        principal_variation.clear();
    }
    commentary.push_back(principal_variation);

    return result.move;
}

bool better_than(const Game_Tree_Node_Result& a, const Game_Tree_Node_Result& b, Color perspective)
{
    auto scoreA = a.corrected_score(perspective);
    auto scoreB = b.corrected_score(perspective);

    if(scoreA > scoreB)
    {
        return true;
    }

    if(scoreA < scoreB)
    {
        return false;
    }

    // scoreA == scoreB

    // Shorter path to winning is better
    if(scoreA == Math::win_score)
    {
        return a.depth < b.depth;
    }

    // Longer path to losing is better
    if(scoreA == Math::lose_score)
    {
        return a.depth > b.depth;
    }

    return false;
}

bool operator==(const Game_Tree_Node_Result& a, const Game_Tree_Node_Result& b)
{
    auto scoreA = a.corrected_score(WHITE);
    auto scoreB = b.corrected_score(WHITE);

    if(scoreA != scoreB)
    {
        return false;
    }

    // scoreA == scoreB

    if(std::abs(scoreA) == Math::win_score)
    {
        return a.depth == b.depth;
    }

    return true;
}

Game_Tree_Node_Result Genetic_AI::search_game_tree(const Board& board,
                                                   const double time_to_examine,
                                                   const Clock& clock,
                                                   const size_t depth,
                                                   Game_Tree_Node_Result alpha,
                                                   Game_Tree_Node_Result beta) const
{
    auto time_start = clock.time_left(clock.running_for());
    auto all_legal_moves = board.legal_moves();

    // The first item in the principal variation is the last move that
    // this player made. Since then, the opponent has also made a move,
    // so the first item in the principal variation corresponds to the
    // game record item at game_record.size() - 2. The depth of the game
    // tree search increments both the game_record index and the principal
    // variation index in step.
    bool still_on_principal_variation = false;
    if(principal_variation.size() > depth + 2)
    {
        still_on_principal_variation = std::equal(board.get_game_record().end() - 2 - depth,
                                                  board.get_game_record().end(),
                                                  principal_variation.begin());

        if(still_on_principal_variation)
        {
            auto next_principal_variation_move = board.get_complete_move(principal_variation[depth + 2]);
            auto move_iter = std::find(all_legal_moves.begin(),
                                       all_legal_moves.end(),
                                       next_principal_variation_move);

            // Make sure that the principal variation is actually a legal move.
            // This is purely for debugging as special circumstances (i.e., once
            // per several thousand games) cause the principal variation to be
            // invalidated without it being cleared.
            if(move_iter == all_legal_moves.end())
            {
                board.ascii_draw(WHITE);
                board.print_game_record(nullptr,
                                        nullptr,
                                        "",
                                        Game_Result(NONE, "Principal Variation error", false),
                                        0, 0, 0,
                                        Clock());
                auto board_copy = board;
                for(const auto& item : principal_variation)
                {
                    auto move = board_copy.get_complete_move(item);
                    std::cout << move.game_record_item(board_copy) << " ";
                    board_copy.submit_move(move);
                }
                std::cout << '\n' << "Depth: " << depth << '\n'
                          << "Next move in variation: "
                          << next_principal_variation_move.game_record_item(board)
                          << std::endl;
                throw std::runtime_error("ERROR: bad variation code");
            }

            // Put principal variation move at start of list to allow
            // the most pruning later.
            std::iter_swap(all_legal_moves.begin(), move_iter);
        }
    }

    auto perspective = board.whose_turn();
    int moves_examined = 0;
    const auto current_legal_moves_count = all_legal_moves.size();

    Game_Tree_Node_Result best_result = {board.legal_moves().front(),
                                         Math::lose_score,
                                         perspective,
                                         depth,
                                         {}};

    for(const auto& move : all_legal_moves)
    {
        ++nodes_searched;

        auto next_board = board;

        auto move_result = next_board.submit_move(move);
        if(move_result.get_winner() != NONE)
        {
            // Mate in one (try to pick the shortest path to checkmate)
            return {move,
                    genome.evaluate(next_board, move_result, perspective),
                    perspective,
                    depth,
                    {next_board.get_game_record().end() - (depth + 1),
                     next_board.get_game_record().end()}};
        }

        if(alpha.depth <= depth + 2 && alpha.corrected_score(perspective) == Math::win_score)
        {
            // This move will take a longer path to victory
            // than one already found. Use "depth + 2" since,
            // if this move isn't winning (and it isn't, since
            // we're here), then the earliest move that can
            // win is the next one, which is two away (after
            // opponent's move).
            continue;
        }

        int moves_left = current_legal_moves_count - moves_examined;
        double time_left = time_to_examine - (time_start - clock.time_left(clock.running_for()));
        double time_allotted_for_this_move = time_left/moves_left;

        bool recurse;
        if(move_result.game_has_ended())
        {
            recurse = false;
        }
        else if(next_board.legal_moves().size() == 1)
        {
            recurse = true;
        }
        else if(still_on_principal_variation)
        {
            recurse = true;
        }
        else
        {
            recurse = genome.enough_time_to_recurse(time_allotted_for_this_move, next_board);
        }

        Game_Tree_Node_Result result;
        if(recurse)
        {
            result = search_game_tree(next_board,
                                      time_allotted_for_this_move,
                                      clock,
                                      depth + 1,
                                      beta,
                                      alpha);

            // Update last result with this game tree node's data
            result.move = move;
        }
        else
        {
            // Record immediate result without looking ahead further
            result = {move,
                      genome.evaluate(next_board, move_result, perspective),
                      perspective,
                      depth,
                      {next_board.get_game_record().end() - (depth + 1),
                       next_board.get_game_record().end()}};
        }

        if(better_than(result, best_result, perspective))
        {
            best_result = result;
            if(better_than(best_result, alpha, perspective))
            {
                alpha = best_result;
                if(better_than(alpha, beta, perspective) || alpha == beta)
                {
                    break;
                }
                else if(depth % 2 == 0 && board.get_thinking_mode() == CECP)
                {
                    output_thinking_cecp(alpha, clock, perspective);
                }
            }
        }

        ++moves_examined;
        still_on_principal_variation = false; // only the first move is part of the principal variation

        if(clock.time_left(clock.running_for()) < 0)
        {
            break;
        }
    }

    return best_result;
}

void Genetic_AI::mutate()
{
    genome.mutate();
}

void Genetic_AI::print_genome(const std::string& file_name) const
{
    if(file_name.empty())
    {
        print_genome(std::cout);
    }
    else
    {
        auto dest = std::ofstream(file_name, std::ofstream::app);
        print_genome(dest);
    }
}

void Genetic_AI::print_genome(std::ostream& os) const
{
    os << "ID: " << get_id() << std::endl;
    genome.print(os);
    os << "END" << std::endl << std::endl;
}

std::string Genetic_AI::name() const
{
    return "Genetic AI " + std::to_string(get_id());
}

std::string Genetic_AI::author() const
{
    return "Mark Harrison";
}

int Genetic_AI::get_id() const
{
    return id;
}

bool Genetic_AI::operator<(const Genetic_AI& other) const
{
    return get_id() < other.get_id();
}

bool Genetic_AI::operator==(const Genetic_AI& other) const
{
    return get_id() == other.get_id();
}

std::string Genetic_AI::get_commentary_for_move(size_t move_number) const
{
    std::string result;
    if(move_number < commentary.size() && ! commentary.at(move_number).empty())
    {
        result = commentary.at(move_number).front();
        for(size_t i = 1; i < commentary.at(move_number).size(); ++i)
        {
            result += " " + commentary.at(move_number).at(i);
        }
    }

    return result;
}

void Genetic_AI::output_thinking_cecp(const Game_Tree_Node_Result& thought,
                                      const Clock& clock,
                                      Color perspective) const
{
    auto score = thought.corrected_score(perspective);
    if(score == Math::win_score)
    {
        score = 10000.0 - thought.depth;
    }
    else if(score == Math::lose_score)
    {
        score = -(10000.0 - thought.depth);
    }

    std::cout << thought.depth // ply
              << " "
              << int(score) // score in what should be centipawns
              << " "
              << int((clock_start_time - clock.time_left(clock.running_for()))*100) // search time in centiseconds
              << " "
              << nodes_searched; // number of nodes searched

    // Principal variation
    for(const auto& move : thought.commentary)
    {
        std::cout << " " << move;
    }

    std::cout << '\n';
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TEST_HPP
#define TEST_HPP

#include <boost/config.hpp>
#include <exception>
#include <sstream>

#include "libtorrent/config.hpp"

#ifdef TORRENT_BUILDING_TEST_SHARED
#define EXPORT BOOST_SYMBOL_EXPORT
#else
#define EXPORT BOOST_SYMBOL_IMPORT
#endif

#if defined(_MSC_VER)
#define COUNTER_GUARD(x)
#else
#define COUNTER_GUARD(type) \
    struct BOOST_PP_CAT(type, _counter_guard) \
    { \
        ~BOOST_PP_CAT(type, _counter_guard()) \
        { \
            TEST_CHECK(counted_type<type>::count == 0); \
        } \
    } BOOST_PP_CAT(type, _guard)
#endif

#define TEST_REPORT_AUX(x, line, file) \
	report_failure(x, line, file)

#ifdef BOOST_NO_EXCEPTIONS
#define TEST_CHECK(x) \
	if (!(x)) \
		TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__);
#define TEST_EQUAL(x, y) \
	if (x != y) { \
		std::stringstream s__; \
		s__ << "TEST_EQUAL_ERROR:\n" #x ": " << x << "\nexpected: " << y << std::endl; \
		TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
	}
#else
#define TEST_CHECK(x) \
	try \
	{ \
		if (!(x)) \
			TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__); \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#define TEST_EQUAL(x, y) \
	try { \
		if (x != y) { \
			std::stringstream s__; \
			s__ << "TEST_EQUAL_ERROR: " #x ": " << x << " expected: " << y << std::endl; \
			TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
		} \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}
#endif

#define TEST_ERROR(x) \
	TEST_REPORT_AUX((std::string("ERROR: \"") + x + "\"").c_str(), __FILE__, __LINE__)

#define TEST_NOTHROW(x) \
	try \
	{ \
		x; \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#endif // TEST_HPP

<commit_msg>fix test header issue<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TEST_HPP
#define TEST_HPP

#include <boost/config.hpp>
#include <exception>
#include <sstream>

#include "libtorrent/config.hpp"

#ifdef TORRENT_BUILDING_TEST_SHARED
#define EXPORT BOOST_SYMBOL_EXPORT
#else
#define EXPORT BOOST_SYMBOL_IMPORT
#endif

void EXPORT report_failure(char const* err, char const* file, int line);

#if defined(_MSC_VER)
#define COUNTER_GUARD(x)
#else
#define COUNTER_GUARD(type) \
    struct BOOST_PP_CAT(type, _counter_guard) \
    { \
        ~BOOST_PP_CAT(type, _counter_guard()) \
        { \
            TEST_CHECK(counted_type<type>::count == 0); \
        } \
    } BOOST_PP_CAT(type, _guard)
#endif

#define TEST_REPORT_AUX(x, line, file) \
	report_failure(x, line, file)

#ifdef BOOST_NO_EXCEPTIONS
#define TEST_CHECK(x) \
	if (!(x)) \
		TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__);
#define TEST_EQUAL(x, y) \
	if (x != y) { \
		std::stringstream s__; \
		s__ << "TEST_EQUAL_ERROR:\n" #x ": " << x << "\nexpected: " << y << std::endl; \
		TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
	}
#else
#define TEST_CHECK(x) \
	try \
	{ \
		if (!(x)) \
			TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__); \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#define TEST_EQUAL(x, y) \
	try { \
		if (x != y) { \
			std::stringstream s__; \
			s__ << "TEST_EQUAL_ERROR: " #x ": " << x << " expected: " << y << std::endl; \
			TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
		} \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}
#endif

#define TEST_ERROR(x) \
	TEST_REPORT_AUX((std::string("ERROR: \"") + x + "\"").c_str(), __FILE__, __LINE__)

#define TEST_NOTHROW(x) \
	try \
	{ \
		x; \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#endif // TEST_HPP

<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/framework/op_desc.h"
#include "paddle/framework/block_desc.h"

namespace paddle {
namespace framework {

OpDescBind::OpDescBind(const std::string &type, const VariableNameMap &inputs,
                       const VariableNameMap &outputs,
                       const AttributeMap &attrs) {
  op_desc_.set_type(type);
  inputs_ = inputs;
  outputs_ = outputs;
  attrs_ = attrs;
}

OpDesc *OpDescBind::Proto() {
  Sync();
  return &op_desc_;
}

const std::vector<std::string> &OpDescBind::Input(
    const std::string &name) const {
  auto it = inputs_.find(name);
  PADDLE_ENFORCE(it != inputs_.end(), "Input %s cannot be found in Op %s", name,
                 Type());
  return it->second;
}

std::vector<std::string> OpDescBind::InputArgumentNames() const {
  std::vector<std::string> retv;
  for (auto &ipt : this->inputs_) {
    retv.insert(retv.end(), ipt.second.begin(), ipt.second.end());
  }
  return retv;
}

void OpDescBind::SetInput(const std::string &param_name,
                          const std::vector<std::string> &args) {
  need_update_ = true;
  inputs_[param_name] = args;
}

const std::vector<std::string> &OpDescBind::Output(
    const std::string &name) const {
  auto it = outputs_.find(name);
  PADDLE_ENFORCE(it != outputs_.end(), "Output %s cannot be found in Op %s",
                 name, Type());
  return it->second;
}

std::vector<std::string> OpDescBind::OutputArgumentNames() const {
  std::vector<std::string> retv;
  for (auto &ipt : this->outputs_) {
    retv.insert(retv.end(), ipt.second.begin(), ipt.second.end());
  }
  return retv;
}

void OpDescBind::SetOutput(const std::string &param_name,
                           const std::vector<std::string> &args) {
  need_update_ = true;
  this->outputs_[param_name] = args;
}

AttrType OpDescBind::GetAttrType(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return static_cast<AttrType>(it->second.which() - 1);
}

std::vector<std::string> OpDescBind::AttrNames() const {
  std::vector<std::string> retv;
  retv.reserve(attrs_.size());
  for (auto &attr : attrs_) {
    retv.push_back(attr.first);
  }
  return retv;
}

void OpDescBind::SetAttr(const std::string &name, const Attribute &v) {
  this->attrs_[name] = v;
  need_update_ = true;
}

void OpDescBind::SetAttrMap(
    const std::unordered_map<std::string, Attribute> &attr_map) {
  attrs_ = attr_map;
  need_update_ = true;
}

Attribute OpDescBind::GetAttr(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return it->second;
}

int OpDescBind::GetBlockAttr(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return boost::get<BlockDesc *>(it->second)->idx();
}

const std::unordered_map<std::string, Attribute> &OpDescBind::GetAttrMap()
    const {
  return attrs_;
}

void OpDescBind::Rename(const std::string &old_name,
                        const std::string &new_name) {
  for (auto &input : inputs_) {
    std::replace(input.second.begin(), input.second.end(), old_name, new_name);
  }
  for (auto &output : outputs_) {
    std::replace(output.second.begin(), output.second.end(), old_name,
                 new_name);
  }
  need_update_ = true;
}

struct SetAttrDescVisitor : public boost::static_visitor<void> {
  explicit SetAttrDescVisitor(OpDesc::Attr *attr) : attr_(attr) {}
  mutable OpDesc::Attr *attr_;
  void operator()(int v) const { attr_->set_i(v); }
  void operator()(float v) const { attr_->set_f(v); }
  void operator()(const std::string &v) const { attr_->set_s(v); }
  void operator()(bool b) const { attr_->set_b(b); }

  void operator()(const std::vector<int> &v) const {
    VectorToRepeated(v, attr_->mutable_ints());
  }
  void operator()(const std::vector<float> &v) const {
    VectorToRepeated(v, attr_->mutable_floats());
  }
  void operator()(const std::vector<std::string> &v) const {
    VectorToRepeated(v, attr_->mutable_strings());
  }
  void operator()(const std::vector<bool> &v) const {
    VectorToRepeated(v, attr_->mutable_bools());
  }
  void operator()(BlockDesc *desc) const { attr_->set_block_idx(desc->idx()); }
  void operator()(boost::blank) const { PADDLE_THROW("Unexpected branch"); }
};

void OpDescBind::Sync() {
  if (need_update_) {
    this->op_desc_.mutable_inputs()->Clear();
    for (auto &ipt : inputs_) {
      auto *input = op_desc_.add_inputs();
      input->set_parameter(ipt.first);
      VectorToRepeated(ipt.second, input->mutable_arguments());
    }

    this->op_desc_.mutable_outputs()->Clear();
    for (auto &opt : outputs_) {
      auto *output = op_desc_.add_outputs();
      output->set_parameter(opt.first);
      VectorToRepeated(opt.second, output->mutable_arguments());
    }

    this->op_desc_.mutable_attrs()->Clear();
    for (auto &attr : attrs_) {
      auto *attr_desc = op_desc_.add_attrs();
      attr_desc->set_name(attr.first);
      attr_desc->set_type(
          static_cast<framework::AttrType>(attr.second.which() - 1));
      SetAttrDescVisitor visitor(attr_desc);
      boost::apply_visitor(visitor, attr.second);
    }

    need_update_ = false;
  }
}
}  // namespace framework
}  // namespace paddle
<commit_msg>Fix bug<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/framework/op_desc.h"
#include "paddle/framework/block_desc.h"

namespace paddle {
namespace framework {

OpDescBind::OpDescBind(const std::string &type, const VariableNameMap &inputs,
                       const VariableNameMap &outputs,
                       const AttributeMap &attrs) {
  op_desc_.set_type(type);
  inputs_ = inputs;
  outputs_ = outputs;
  attrs_ = attrs;
  need_update_ = true;
}

OpDesc *OpDescBind::Proto() {
  Sync();
  return &op_desc_;
}

const std::vector<std::string> &OpDescBind::Input(
    const std::string &name) const {
  auto it = inputs_.find(name);
  PADDLE_ENFORCE(it != inputs_.end(), "Input %s cannot be found in Op %s", name,
                 Type());
  return it->second;
}

std::vector<std::string> OpDescBind::InputArgumentNames() const {
  std::vector<std::string> retv;
  for (auto &ipt : this->inputs_) {
    retv.insert(retv.end(), ipt.second.begin(), ipt.second.end());
  }
  return retv;
}

void OpDescBind::SetInput(const std::string &param_name,
                          const std::vector<std::string> &args) {
  need_update_ = true;
  inputs_[param_name] = args;
}

const std::vector<std::string> &OpDescBind::Output(
    const std::string &name) const {
  auto it = outputs_.find(name);
  PADDLE_ENFORCE(it != outputs_.end(), "Output %s cannot be found in Op %s",
                 name, Type());
  return it->second;
}

std::vector<std::string> OpDescBind::OutputArgumentNames() const {
  std::vector<std::string> retv;
  for (auto &ipt : this->outputs_) {
    retv.insert(retv.end(), ipt.second.begin(), ipt.second.end());
  }
  return retv;
}

void OpDescBind::SetOutput(const std::string &param_name,
                           const std::vector<std::string> &args) {
  need_update_ = true;
  this->outputs_[param_name] = args;
}

AttrType OpDescBind::GetAttrType(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return static_cast<AttrType>(it->second.which() - 1);
}

std::vector<std::string> OpDescBind::AttrNames() const {
  std::vector<std::string> retv;
  retv.reserve(attrs_.size());
  for (auto &attr : attrs_) {
    retv.push_back(attr.first);
  }
  return retv;
}

void OpDescBind::SetAttr(const std::string &name, const Attribute &v) {
  this->attrs_[name] = v;
  need_update_ = true;
}

void OpDescBind::SetAttrMap(
    const std::unordered_map<std::string, Attribute> &attr_map) {
  attrs_ = attr_map;
  need_update_ = true;
}

Attribute OpDescBind::GetAttr(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return it->second;
}

int OpDescBind::GetBlockAttr(const std::string &name) const {
  auto it = attrs_.find(name);
  PADDLE_ENFORCE(it != attrs_.end(), "Attribute %s is not found", name);
  return boost::get<BlockDesc *>(it->second)->idx();
}

const std::unordered_map<std::string, Attribute> &OpDescBind::GetAttrMap()
    const {
  return attrs_;
}

void OpDescBind::Rename(const std::string &old_name,
                        const std::string &new_name) {
  for (auto &input : inputs_) {
    std::replace(input.second.begin(), input.second.end(), old_name, new_name);
  }
  for (auto &output : outputs_) {
    std::replace(output.second.begin(), output.second.end(), old_name,
                 new_name);
  }
  need_update_ = true;
}

struct SetAttrDescVisitor : public boost::static_visitor<void> {
  explicit SetAttrDescVisitor(OpDesc::Attr *attr) : attr_(attr) {}
  mutable OpDesc::Attr *attr_;
  void operator()(int v) const { attr_->set_i(v); }
  void operator()(float v) const { attr_->set_f(v); }
  void operator()(const std::string &v) const { attr_->set_s(v); }
  void operator()(bool b) const { attr_->set_b(b); }

  void operator()(const std::vector<int> &v) const {
    VectorToRepeated(v, attr_->mutable_ints());
  }
  void operator()(const std::vector<float> &v) const {
    VectorToRepeated(v, attr_->mutable_floats());
  }
  void operator()(const std::vector<std::string> &v) const {
    VectorToRepeated(v, attr_->mutable_strings());
  }
  void operator()(const std::vector<bool> &v) const {
    VectorToRepeated(v, attr_->mutable_bools());
  }
  void operator()(BlockDesc *desc) const { attr_->set_block_idx(desc->idx()); }
  void operator()(boost::blank) const { PADDLE_THROW("Unexpected branch"); }
};

void OpDescBind::Sync() {
  if (need_update_) {
    this->op_desc_.mutable_inputs()->Clear();
    for (auto &ipt : inputs_) {
      auto *input = op_desc_.add_inputs();
      input->set_parameter(ipt.first);
      VectorToRepeated(ipt.second, input->mutable_arguments());
    }

    this->op_desc_.mutable_outputs()->Clear();
    for (auto &opt : outputs_) {
      auto *output = op_desc_.add_outputs();
      output->set_parameter(opt.first);
      VectorToRepeated(opt.second, output->mutable_arguments());
    }

    this->op_desc_.mutable_attrs()->Clear();
    for (auto &attr : attrs_) {
      auto *attr_desc = op_desc_.add_attrs();
      attr_desc->set_name(attr.first);
      attr_desc->set_type(
          static_cast<framework::AttrType>(attr.second.which() - 1));
      SetAttrDescVisitor visitor(attr_desc);
      boost::apply_visitor(visitor, attr.second);
    }

    need_update_ = false;
  }
}
}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2017 Robert Ou <rqou@robertou.com>
 *
 *  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 "kernel/yosys.h"
#include "kernel/sigtools.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct RecoverReduceCorePass : public Pass {
	enum GateType {
		And,
		Or,
		Xor
	};

	RecoverReduceCorePass() : Pass("recover_reduce_core", "converts gate chains into $reduce_*") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    recover_reduce_core\n");
		log("\n");
		log("converts gate chains into $reduce_*\n");
		log("\n");
		log("This performs the core step of the recover_reduce command. This step recognizes\n");
		log("chains of gates found by the previous steps and converts these chains into one\n");
		log("logical cell.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		(void)args;

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);

			// Index all of the nets in the module
			dict<SigBit, Cell*> sig_to_driver;
			dict<SigBit, pool<Cell*>> sig_to_sink;
			for (auto cell : module->selected_cells())
			{
				for (auto &conn : cell->connections())
				{
					if (cell->output(conn.first))
						for (auto bit : sigmap(conn.second))
							sig_to_driver[bit] = cell;

					if (cell->input(conn.first))
					{
						for (auto bit : sigmap(conn.second))
						{
							if (sig_to_sink.count(bit) == 0)
								sig_to_sink[bit] = pool<Cell*>();
							sig_to_sink[bit].insert(cell);
						}
					}
				}
			}

			// Need to check if any wires connect to module ports
			pool<SigBit> port_sigs;
			for (auto wire : module->selected_wires())
				if (wire->port_input || wire->port_output)
					for (auto bit : sigmap(wire))
						port_sigs.insert(bit);

			// Actual logic starts here
			pool<Cell*> consumed_cells;
			for (auto cell : module->selected_cells())
			{
				if (consumed_cells.count(cell))
					continue;

				GateType gt;

				if (cell->type == "$_AND_")
					gt = GateType::And;
				else if (cell->type == "$_OR_")
					gt = GateType::Or;
				else if (cell->type == "$_XOR_")
					gt = GateType::Xor;
				else
					continue;

				log("Working on cell %s...\n", cell->name.c_str());

				// Go all the way to the sink
				Cell* head_cell = cell;
				Cell* x = cell;
				while (true)
				{
					if (!((x->type == "$_AND_" && gt == GateType::And) ||
						(x->type == "$_OR_" && gt == GateType::Or) ||
						(x->type == "$_XOR_" && gt == GateType::Xor)))
						break;

					head_cell = x;

					auto y = sigmap(x->getPort("\\Y"));
					log_assert(y.size() == 1);

					// Should only continue if there is one fanout back into a cell (not to a port)
					if (sig_to_sink[y[0]].size() != 1)
						break;

					x = *sig_to_sink[y[0]].begin();
				}

				log("  Head cell is %s\n", head_cell->name.c_str());

				pool<Cell*> cur_supercell;
				std::deque<Cell*> bfs_queue = {head_cell};
				while (bfs_queue.size())
				{
					Cell* x = bfs_queue.front();
					bfs_queue.pop_front();

					cur_supercell.insert(x);

					auto a = sigmap(x->getPort("\\A"));
					log_assert(a.size() == 1);
					// Must have only one sink
					// XXX: Check that it is indeed this node?
					if (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1)
					{
						Cell* cell_a = sig_to_driver[a[0]];
						if (((cell_a->type == "$_AND_" && gt == GateType::And) ||
							(cell_a->type == "$_OR_" && gt == GateType::Or) ||
							(cell_a->type == "$_XOR_" && gt == GateType::Xor)))
						{
							// The cell here is the correct type, and it's definitely driving only
							// this current cell.
							bfs_queue.push_back(cell_a);
						}
					}

					auto b = sigmap(x->getPort("\\B"));
					log_assert(b.size() == 1);
					// Must have only one sink
					// XXX: Check that it is indeed this node?
					if (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1)
					{
						Cell* cell_b = sig_to_driver[b[0]];
						if (((cell_b->type == "$_AND_" && gt == GateType::And) ||
							(cell_b->type == "$_OR_" && gt == GateType::Or) ||
							(cell_b->type == "$_XOR_" && gt == GateType::Xor)))
						{
							// The cell here is the correct type, and it's definitely driving only
							// this current cell.
							bfs_queue.push_back(cell_b);
						}
					}
				}

				log("  Cells:\n");
				for (auto x : cur_supercell)
					log("    %s\n", x->name.c_str());

				if (cur_supercell.size() > 1)
				{
					// Worth it to create reduce cell
					log("  Creating $reduce_* cell!\n");

					pool<SigBit> input_pool;
					pool<SigBit> input_pool_intermed;
					for (auto x : cur_supercell)
					{
						input_pool.insert(sigmap(x->getPort("\\A"))[0]);
						input_pool.insert(sigmap(x->getPort("\\B"))[0]);
						input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]);
					}
					SigSpec input;
					for (auto b : input_pool)
						if (input_pool_intermed.count(b) == 0)
							input.append_bit(b);

					SigBit output = sigmap(head_cell->getPort("\\Y")[0]);

					auto new_reduce_cell = module->addCell(NEW_ID,
						gt == GateType::And ? "$reduce_and" :
						gt == GateType::Or ? "$reduce_or" :
						gt == GateType::Xor ? "$reduce_xor" : "");
					new_reduce_cell->setParam("\\A_SIGNED", 0);
					new_reduce_cell->setParam("\\A_WIDTH", input.size());
					new_reduce_cell->setParam("\\Y_WIDTH", 1);
					new_reduce_cell->setPort("\\A", input);
					new_reduce_cell->setPort("\\Y", output);

					for (auto x : cur_supercell)
						consumed_cells.insert(x);
					}
				}

			// Remove every cell that we've used up
			for (auto cell : consumed_cells)
				module->remove(cell);
		}
	}
} RecoverReduceCorePass;

PRIVATE_NAMESPACE_END
<commit_msg>recover_reduce: Update documentation<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2017 Robert Ou <rqou@robertou.com>
 *
 *  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 "kernel/yosys.h"
#include "kernel/sigtools.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct RecoverReducePass : public Pass {
	enum GateType {
		And,
		Or,
		Xor
	};

	RecoverReducePass() : Pass("recover_reduce", "converts gate chains into $reduce_* cells") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    recover_reduce\n");
		log("\n");
		log("converts gate chains into $reduce_* cells\n");
		log("\n");
		log("This command finds chains of $_AND_, $_OR_, and $_XOR_ cells and replaces them\n");
		log("with their corresponding $reduce_* cells. Because this command only operates on\n");
		log("these cell types, it is recommended to map the design to only these cell types\n");
		log("using the `abc -g` command. Note that, in some cases, it may be more effective\n");
		log("to map the design to only $_AND_ cells, run recover_reduce, map the remaining\n");
		log("parts of the design to AND/OR/XOR cells, and run recover_reduce a second time.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		(void)args;

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);

			// Index all of the nets in the module
			dict<SigBit, Cell*> sig_to_driver;
			dict<SigBit, pool<Cell*>> sig_to_sink;
			for (auto cell : module->selected_cells())
			{
				for (auto &conn : cell->connections())
				{
					if (cell->output(conn.first))
						for (auto bit : sigmap(conn.second))
							sig_to_driver[bit] = cell;

					if (cell->input(conn.first))
					{
						for (auto bit : sigmap(conn.second))
						{
							if (sig_to_sink.count(bit) == 0)
								sig_to_sink[bit] = pool<Cell*>();
							sig_to_sink[bit].insert(cell);
						}
					}
				}
			}

			// Need to check if any wires connect to module ports
			pool<SigBit> port_sigs;
			for (auto wire : module->selected_wires())
				if (wire->port_input || wire->port_output)
					for (auto bit : sigmap(wire))
						port_sigs.insert(bit);

			// Actual logic starts here
			pool<Cell*> consumed_cells;
			for (auto cell : module->selected_cells())
			{
				if (consumed_cells.count(cell))
					continue;

				GateType gt;

				if (cell->type == "$_AND_")
					gt = GateType::And;
				else if (cell->type == "$_OR_")
					gt = GateType::Or;
				else if (cell->type == "$_XOR_")
					gt = GateType::Xor;
				else
					continue;

				log("Working on cell %s...\n", cell->name.c_str());

				// Go all the way to the sink
				Cell* head_cell = cell;
				Cell* x = cell;
				while (true)
				{
					if (!((x->type == "$_AND_" && gt == GateType::And) ||
						(x->type == "$_OR_" && gt == GateType::Or) ||
						(x->type == "$_XOR_" && gt == GateType::Xor)))
						break;

					head_cell = x;

					auto y = sigmap(x->getPort("\\Y"));
					log_assert(y.size() == 1);

					// Should only continue if there is one fanout back into a cell (not to a port)
					if (sig_to_sink[y[0]].size() != 1)
						break;

					x = *sig_to_sink[y[0]].begin();
				}

				log("  Head cell is %s\n", head_cell->name.c_str());

				pool<Cell*> cur_supercell;
				std::deque<Cell*> bfs_queue = {head_cell};
				while (bfs_queue.size())
				{
					Cell* x = bfs_queue.front();
					bfs_queue.pop_front();

					cur_supercell.insert(x);

					auto a = sigmap(x->getPort("\\A"));
					log_assert(a.size() == 1);
					// Must have only one sink
					// XXX: Check that it is indeed this node?
					if (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1)
					{
						Cell* cell_a = sig_to_driver[a[0]];
						if (((cell_a->type == "$_AND_" && gt == GateType::And) ||
							(cell_a->type == "$_OR_" && gt == GateType::Or) ||
							(cell_a->type == "$_XOR_" && gt == GateType::Xor)))
						{
							// The cell here is the correct type, and it's definitely driving only
							// this current cell.
							bfs_queue.push_back(cell_a);
						}
					}

					auto b = sigmap(x->getPort("\\B"));
					log_assert(b.size() == 1);
					// Must have only one sink
					// XXX: Check that it is indeed this node?
					if (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1)
					{
						Cell* cell_b = sig_to_driver[b[0]];
						if (((cell_b->type == "$_AND_" && gt == GateType::And) ||
							(cell_b->type == "$_OR_" && gt == GateType::Or) ||
							(cell_b->type == "$_XOR_" && gt == GateType::Xor)))
						{
							// The cell here is the correct type, and it's definitely driving only
							// this current cell.
							bfs_queue.push_back(cell_b);
						}
					}
				}

				log("  Cells:\n");
				for (auto x : cur_supercell)
					log("    %s\n", x->name.c_str());

				if (cur_supercell.size() > 1)
				{
					// Worth it to create reduce cell
					log("  Creating $reduce_* cell!\n");

					pool<SigBit> input_pool;
					pool<SigBit> input_pool_intermed;
					for (auto x : cur_supercell)
					{
						input_pool.insert(sigmap(x->getPort("\\A"))[0]);
						input_pool.insert(sigmap(x->getPort("\\B"))[0]);
						input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]);
					}
					SigSpec input;
					for (auto b : input_pool)
						if (input_pool_intermed.count(b) == 0)
							input.append_bit(b);

					SigBit output = sigmap(head_cell->getPort("\\Y")[0]);

					auto new_reduce_cell = module->addCell(NEW_ID,
						gt == GateType::And ? "$reduce_and" :
						gt == GateType::Or ? "$reduce_or" :
						gt == GateType::Xor ? "$reduce_xor" : "");
					new_reduce_cell->setParam("\\A_SIGNED", 0);
					new_reduce_cell->setParam("\\A_WIDTH", input.size());
					new_reduce_cell->setParam("\\Y_WIDTH", 1);
					new_reduce_cell->setPort("\\A", input);
					new_reduce_cell->setPort("\\Y", output);

					for (auto x : cur_supercell)
						consumed_cells.insert(x);
					}
				}

			// Remove every cell that we've used up
			for (auto cell : consumed_cells)
				module->remove(cell);
		}
	}
} RecoverReducePass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>#include "BluPrivatePCH.h"

class FBlu : public IBlu
{

	/** IModuleInterface implementation */
	virtual void StartupModule() override
	{

		FString GameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir() + "BluCache");
		CefString GameDirCef = *GameDir;

		// Setup the default settings for BluManager
		BluManager::settings.windowless_rendering_enabled = true;
		BluManager::settings.no_sandbox = true;

		BluManager::settings.remote_debugging_port = 7777;

#if PLATFORM_LINUX
		CefString(&BluManager::settings.browser_subprocess_path).FromASCII("./blu_ue4_process");
#endif
#if PLATFORM_WINDOWS
		CefString(&BluManager::settings.browser_subprocess_path).FromASCII("./blu_ue4_process.exe");
#endif
		CefString(&BluManager::settings.cache_path).FromString(GameDirCef);

		CefExecuteProcess(BluManager::main_args, NULL, NULL);
		CefInitialize(BluManager::main_args, BluManager::settings, NULL, NULL);

		UE_LOG(LogBlu, Log, TEXT(" STATUS: Loaded"));
	}

	virtual void ShutdownModule() override
	{
		UE_LOG(LogBlu, Log, TEXT(" STATUS: Shutdown"));
		CefShutdown();
	}

};

IMPLEMENT_MODULE( FBlu, Blu )
DEFINE_LOG_CATEGORY(LogBlu);<commit_msg>Allow multi-thread message loop<commit_after>#include "BluPrivatePCH.h"

class FBlu : public IBlu
{

	/** IModuleInterface implementation */
	virtual void StartupModule() override
	{

		FString GameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir() + "BluCache");
		CefString GameDirCef = *GameDir;

		// Setup the default settings for BluManager
		BluManager::settings.windowless_rendering_enabled = true;
		BluManager::settings.no_sandbox = true;
		BluManager::settings.multi_threaded_message_loop = 1;
		BluManager::settings.remote_debugging_port = 7777;

#if PLATFORM_LINUX
		CefString(&BluManager::settings.browser_subprocess_path).FromASCII("./blu_ue4_process");
#endif
#if PLATFORM_WINDOWS
		CefString(&BluManager::settings.browser_subprocess_path).FromASCII("./blu_ue4_process.exe");
#endif
		CefString(&BluManager::settings.cache_path).FromString(GameDirCef);

		CefExecuteProcess(BluManager::main_args, NULL, NULL);
		CefInitialize(BluManager::main_args, BluManager::settings, NULL, NULL);

		UE_LOG(LogBlu, Log, TEXT(" STATUS: Loaded"));
	}

	virtual void ShutdownModule() override
	{
		UE_LOG(LogBlu, Log, TEXT(" STATUS: Shutdown"));
		CefShutdown();
	}

};

IMPLEMENT_MODULE( FBlu, Blu )
DEFINE_LOG_CATEGORY(LogBlu);<|endoftext|>


<commit_before>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_RESULT_HPP__
#define __STOUT_RESULT_HPP__

#include <assert.h>
#include <stdlib.h> // For abort.

#include <iostream>
#include <string>

#include <stout/error.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/some.hpp>

template <typename T>
class Result
{
public:
  static Result<T> none()
  {
    return Result<T>(NONE);
  }

  static Result<T> some(const T& t)
  {
    return Result<T>(SOME, new T(t));
  }

  static Result<T> error(const std::string& message)
  {
    return Result<T>(ERROR, NULL, message);
  }

  Result(const T& _t)
    : state(SOME), t(new T(_t)) {}

  template <typename U>
  Result(const U& u)
    : state(SOME), t(new T(u)) {}

  Result(const Option<T>& option)
    : state(option.isSome() ? SOME : NONE),
      t(option.isSome() ? new T(option.get()) : NULL) {}

  Result(const None& none)
    : state(NONE), t(NULL) {}

  template <typename U>
  Result(const _Some<U>& some)
    : state(SOME), t(new T(some.t)) {}

  Result(const Error& error)
    : state(ERROR), t(NULL), message(error.message) {}

  Result(const ErrnoError& error)
    : state(ERROR), t(NULL), message(error.message) {}

  Result(const Result<T>& that)
  {
    state = that.state;
    if (that.t != NULL) {
      t = new T(*that.t);
    } else {
      t = NULL;
    }
    message = that.message;
  }

  ~Result()
  {
    delete t;
  }

  Result<T>& operator = (const Result<T>& that)
  {
    if (this != &that) {
      delete t;
      state = that.state;
      if (that.t != NULL) {
        t = new T(*that.t);
      } else {
        t = NULL;
      }
      message = that.message;
    }

    return *this;
  }

  bool isSome() const { return state == SOME; }
  bool isNone() const { return state == NONE; }
  bool isError() const { return state == ERROR; }

  T get() const
  {
    if (state != SOME) {
      if (state == ERROR) {
        std::cerr << "Result::get() but state == ERROR: "
                  << error() << std::endl;
      } else if (state == NONE) {
        std::cerr << "Result::get() but state == NONE" << std::endl;
      }
      abort();
    }
    return *t;
  }

  std::string error() const { assert(state == ERROR); return message; }

private:
  enum State {
    SOME,
    NONE,
    ERROR
  };

  Result(State _state, T* _t = NULL, const std::string& _message = "")
    : state(_state), t(_t), message(_message) {}

  State state;
  T* t;
  std::string message;
};

#endif // __STOUT_RESULT_HPP__
<commit_msg>Changed Result::get to return a const reference.<commit_after>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_RESULT_HPP__
#define __STOUT_RESULT_HPP__

#include <assert.h>
#include <stdlib.h> // For abort.

#include <iostream>
#include <string>

#include <stout/error.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/some.hpp>

template <typename T>
class Result
{
public:
  static Result<T> none()
  {
    return Result<T>(NONE);
  }

  static Result<T> some(const T& t)
  {
    return Result<T>(SOME, new T(t));
  }

  static Result<T> error(const std::string& message)
  {
    return Result<T>(ERROR, NULL, message);
  }

  Result(const T& _t)
    : state(SOME), t(new T(_t)) {}

  template <typename U>
  Result(const U& u)
    : state(SOME), t(new T(u)) {}

  Result(const Option<T>& option)
    : state(option.isSome() ? SOME : NONE),
      t(option.isSome() ? new T(option.get()) : NULL) {}

  Result(const None& none)
    : state(NONE), t(NULL) {}

  template <typename U>
  Result(const _Some<U>& some)
    : state(SOME), t(new T(some.t)) {}

  Result(const Error& error)
    : state(ERROR), t(NULL), message(error.message) {}

  Result(const ErrnoError& error)
    : state(ERROR), t(NULL), message(error.message) {}

  Result(const Result<T>& that)
  {
    state = that.state;
    t = (that.t == NULL ? NULL : new T(*that.t));
    message = that.message;
  }

  ~Result()
  {
    delete t;
  }

  Result<T>& operator = (const Result<T>& that)
  {
    if (this != &that) {
      delete t;
      state = that.state;
      t = (that.t == NULL ? NULL : new T(*that.t));
      message = that.message;
    }

    return *this;
  }

  bool isSome() const { return state == SOME; }
  bool isNone() const { return state == NONE; }
  bool isError() const { return state == ERROR; }

  const T& get() const
  {
    // TODO(dhamon): Switch this to fatal() once that calls abort().
    if (state != SOME) {
      if (state == ERROR) {
        std::cerr << "Result::get() but state == ERROR: "
                  << error() << std::endl;
      } else if (state == NONE) {
        std::cerr << "Result::get() but state == NONE" << std::endl;
      }
      abort();
    }
    return *t;
  }

  // TODO(dhamon): Return const std::string& to remove copy.
  std::string error() const { assert(state == ERROR); return message; }

private:
  enum State {
    SOME,
    NONE,
    ERROR
  };

  Result(State _state, T* _t = NULL, const std::string& _message = "")
    : state(_state), t(_t), message(_message) {}

  State state;
  T* t;
  std::string message;
};

#endif // __STOUT_RESULT_HPP__
<|endoftext|>


<commit_before>const static char sccsid[] = "%Z% %W% %I% %E% %U%";
/*********************************************************************/
/*   <copyright                                                       */
/*   notice="oco-source"                                              */
/*   pids="5755-P60"                                                  */
/*   years="2013"                                                     */
/*   crc="2536674324" >                                               */
/*   IBM Confidential                                                 */
/*                                                                    */
/*   OCO Source Materials                                             */
/*                                                                    */
/*   5755-P60                                                         */
/*                                                                    */
/*   (C) Copyright IBM Corp. 2013                                     */
/*                                                                    */
/*   The source code for the program is not published                 */
/*   or otherwise divested of its trade secrets,                      */
/*   irrespective of what has been deposited with the                 */
/*   U.S. Copyright Office.                                           */
/*   </copyright>                                                     */
/*                                                                    */
/**********************************************************************/
/* Following text will be included in the Service Reference Manual.   */
/* Ensure that the content is correct and up-to-date.                 */
/* All updates must be made in mixed case.                            */
/*                                                                    */
/* The functions in this file provide the wrapper functions around    */
/* the Apache Qpid Proton C Message API for use by Node.js            */
/**********************************************************************/
/* End of text to be included in SRM                                  */
/**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "message.hpp"

using namespace v8;
using namespace node;

#define THROW_EXCEPTION(error) \
    const char *msg = error; \
    Local<Value> e = Exception::TypeError(String::New(msg)); \
    return ThrowException(e);

Persistent<FunctionTemplate> ProtonMessage::constructor;

void ProtonMessage::Init(Handle<Object> target)
{
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  constructor = Persistent<FunctionTemplate>::New(tpl);
  constructor->InstanceTemplate()->SetInternalFieldCount(1);
  Local<String> name = String::NewSymbol("ProtonMessage");
  constructor->SetClassName(name);

  NODE_SET_PROTOTYPE_METHOD(constructor, "destroy", Destroy);

  tpl->InstanceTemplate()->SetAccessor(String::New("body"),
      GetBody, PutBody);
  tpl->InstanceTemplate()->SetAccessor(String::New("contentType"),
      GetContentType, SetContentType);
  tpl->InstanceTemplate()->SetAccessor(String::New("address"),
      GetAddress, SetAddress);

  target->Set(name, constructor->GetFunction());
}

ProtonMessage::ProtonMessage() : ObjectWrap()
{
  message = pn_message();
}

ProtonMessage::~ProtonMessage()
{
  if (message)
  {
    pn_message_free(message);
  }
  handle_->SetInternalField(0, Undefined());
  handle_.Dispose();
  handle_.Clear();
}

Handle<Value> ProtonMessage::NewInstance(const Arguments& args)
{
  HandleScope scope;

  Local<Object> instance = constructor->GetFunction()->NewInstance();

  return scope.Close(instance);
}

Handle<Value> ProtonMessage::New(const Arguments& args)
{
  HandleScope scope;

  if (!args.IsConstructCall())
  {
    THROW_EXCEPTION("Use the new operator to create instances of this object.")
  }

  // create a new instance of this type and wrap it in 'this' v8 Object
  ProtonMessage *msg = new ProtonMessage();
  msg->Wrap(args.This());

  return args.This();
}

Handle<Value> ProtonMessage::Destroy(const Arguments& args)
{
  HandleScope scope;
  ProtonMessage *msg;

  msg = ObjectWrap::Unwrap<ProtonMessage>(args.This());
  msg->~ProtonMessage();

  return Undefined();
}

Handle<Value> ProtonMessage::GetAddress(Local<String> property,
                                        const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());
  const char *addr = pn_message_get_address(msg->message);

  return scope.Close(String::New(addr));
}

void ProtonMessage::SetAddress(Local<String> property,
                               Local<Value> value,
                               const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  String::Utf8Value param(value->ToString());
  std::string address = std::string(*param);

  pn_message_set_address(msg->message, address.c_str());
}

Handle<Value> ProtonMessage::GetBody(Local<String> property,
                                     const AccessorInfo &info)
{
  HandleScope scope;
  Local<Value> result;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  // inspect data to see if we have PN_STRING data
  pn_data_next(pn_message_body(msg->message));
  pn_type_t type = pn_data_type(pn_message_body(msg->message));
  if (type == PN_STRING)
  {
    pn_message_set_format(msg->message, PN_TEXT);
  }

  // XXX: maybe cache this in the C++ object at set time?
  char *buffer = (char *) malloc(512 * sizeof(char));
  size_t buffsize = sizeof(buffer);

  // TODO: patch proton to return the required size in buffsize for realloc
  int rc = pn_message_save(msg->message, buffer, &buffsize);
  while (rc == PN_OVERFLOW)
  {
    buffsize = 2*buffsize;
    buffer = (char *) realloc(buffer, buffsize);
    rc = pn_message_save(msg->message, buffer, &buffsize);
  }

  // return appropriate JS object based on type
  switch (type)
  {
    case PN_STRING:
      result = String::New(buffer, (int)buffsize);
      break;
    default:
      Local<Object> global = Context::GetCurrent()->Global();
      Local<Function> constructor = Local<Function>::Cast(global->Get(
            String::New("Buffer")));
      Handle<Value> args[1] = { v8::Integer::New(buffsize) };
      result = constructor->NewInstance(1, args);
      memcpy(Buffer::Data(result), buffer, buffsize);
      break;
  }

#ifdef _DEBUG
    printf("Address: %s\n", pn_message_get_address(msg->message));
    const char *subject = pn_message_get_subject(msg->message);
    printf("Subject: %s\n", subject ? subject : "(no subject)");
    printf("Content: %s\n", buffer);
#endif

  free(buffer);

  return scope.Close(result);
}

void ProtonMessage::PutBody(Local<String> property,
                            Local<Value> value,
                            const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  if (value->IsString()) {
    String::Utf8Value param(value->ToString());
    std::string msgtext = std::string(*param);
    pn_message_set_format(msg->message, PN_TEXT);
    pn_message_load_text(msg->message, msgtext.c_str(), strlen(msgtext.c_str()));
    V8::AdjustAmountOfExternalAllocatedMemory(sizeof(msgtext.c_str()));
  } else if (value->IsObject()) {
    Local<Object> buffer = value->ToObject();
    char *msgdata = Buffer::Data(buffer);
    size_t msglen = Buffer::Length(buffer);
    pn_message_set_format(msg->message, PN_DATA);
    pn_message_load_data(msg->message, msgdata, msglen);
    V8::AdjustAmountOfExternalAllocatedMemory(sizeof(msgdata));
  }
}

Handle<Value> ProtonMessage::GetContentType(Local<String> property,
                                            const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());
  const char *type = pn_message_get_content_type(msg->message);

  return scope.Close(type ? String::New(type) : Null());
}

void ProtonMessage::SetContentType(Local<String> property,
                                   Local<Value> value,
                                   const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  String::Utf8Value param(value->ToString());
  std::string type = std::string(*param);

  pn_message_set_content_type(msg->message, type.c_str());
}
<commit_msg>update ProtonMessage::GetBody to be a bit more resilient to NPEs<commit_after>const static char sccsid[] = "%Z% %W% %I% %E% %U%";
/*********************************************************************/
/*   <copyright                                                       */
/*   notice="oco-source"                                              */
/*   pids="5755-P60"                                                  */
/*   years="2013"                                                     */
/*   crc="2536674324" >                                               */
/*   IBM Confidential                                                 */
/*                                                                    */
/*   OCO Source Materials                                             */
/*                                                                    */
/*   5755-P60                                                         */
/*                                                                    */
/*   (C) Copyright IBM Corp. 2013                                     */
/*                                                                    */
/*   The source code for the program is not published                 */
/*   or otherwise divested of its trade secrets,                      */
/*   irrespective of what has been deposited with the                 */
/*   U.S. Copyright Office.                                           */
/*   </copyright>                                                     */
/*                                                                    */
/**********************************************************************/
/* Following text will be included in the Service Reference Manual.   */
/* Ensure that the content is correct and up-to-date.                 */
/* All updates must be made in mixed case.                            */
/*                                                                    */
/* The functions in this file provide the wrapper functions around    */
/* the Apache Qpid Proton C Message API for use by Node.js            */
/**********************************************************************/
/* End of text to be included in SRM                                  */
/**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "message.hpp"

using namespace v8;
using namespace node;

#define THROW_EXCEPTION(error) \
    const char *msg = error; \
    Local<Value> e = Exception::TypeError(String::New(msg)); \
    return ThrowException(e);

Persistent<FunctionTemplate> ProtonMessage::constructor;

void ProtonMessage::Init(Handle<Object> target)
{
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  constructor = Persistent<FunctionTemplate>::New(tpl);
  constructor->InstanceTemplate()->SetInternalFieldCount(1);
  Local<String> name = String::NewSymbol("ProtonMessage");
  constructor->SetClassName(name);

  NODE_SET_PROTOTYPE_METHOD(constructor, "destroy", Destroy);

  tpl->InstanceTemplate()->SetAccessor(String::New("body"),
      GetBody, PutBody);
  tpl->InstanceTemplate()->SetAccessor(String::New("contentType"),
      GetContentType, SetContentType);
  tpl->InstanceTemplate()->SetAccessor(String::New("address"),
      GetAddress, SetAddress);

  target->Set(name, constructor->GetFunction());
}

ProtonMessage::ProtonMessage() : ObjectWrap()
{
  message = pn_message();
}

ProtonMessage::~ProtonMessage()
{
  if (message)
  {
    pn_message_free(message);
  }
  handle_->SetInternalField(0, Undefined());
  handle_.Dispose();
  handle_.Clear();
}

Handle<Value> ProtonMessage::NewInstance(const Arguments& args)
{
  HandleScope scope;

  Local<Object> instance = constructor->GetFunction()->NewInstance();

  return scope.Close(instance);
}

Handle<Value> ProtonMessage::New(const Arguments& args)
{
  HandleScope scope;

  if (!args.IsConstructCall())
  {
    THROW_EXCEPTION("Use the new operator to create instances of this object.")
  }

  // create a new instance of this type and wrap it in 'this' v8 Object
  ProtonMessage *msg = new ProtonMessage();
  msg->Wrap(args.This());

  return args.This();
}

Handle<Value> ProtonMessage::Destroy(const Arguments& args)
{
  HandleScope scope;
  ProtonMessage *msg;

  msg = ObjectWrap::Unwrap<ProtonMessage>(args.This());
  msg->~ProtonMessage();

  return Undefined();
}

Handle<Value> ProtonMessage::GetAddress(Local<String> property,
                                        const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());
  const char *addr = pn_message_get_address(msg->message);

  return scope.Close(String::New(addr));
}

void ProtonMessage::SetAddress(Local<String> property,
                               Local<Value> value,
                               const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  String::Utf8Value param(value->ToString());
  std::string address = std::string(*param);

  pn_message_set_address(msg->message, address.c_str());
}

Handle<Value> ProtonMessage::GetBody(Local<String> property,
                                     const AccessorInfo &info)
{
  HandleScope scope;
  Handle<Value> result;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  if (msg && msg->message)
  {
    pn_data_t *body = pn_message_body(msg->message);
    // inspect data to see if we have PN_STRING data
    pn_data_next(body);
    pn_type_t type = pn_data_type(body);
    if (type == PN_STRING)
    {
      pn_message_set_format(msg->message, PN_TEXT);
    }

    // XXX: maybe cache this in the C++ object at set time?
    char *buffer = (char *) malloc(512 * sizeof(char));
    size_t buffsize = sizeof(buffer);

    // TODO: patch proton to return the required size in buffsize for realloc
    int rc = pn_message_save(msg->message, buffer, &buffsize);
    while (rc == PN_OVERFLOW)
    {
      buffsize = 2*buffsize;
      buffer = (char *) realloc(buffer, buffsize);
      rc = pn_message_save(msg->message, buffer, &buffsize);
    }

    // return appropriate JS object based on type
    switch (type)
    {
      case PN_STRING:
        result = String::New(buffer, (int)buffsize);
        break;
      default:
        Local<Object> global = Context::GetCurrent()->Global();
        Local<Function> constructor = Local<Function>::Cast(global->Get(
              String::New("Buffer")));
        Handle<Value> args[1] = { v8::Integer::New(buffsize) };
        result = constructor->NewInstance(1, args);
        memcpy(Buffer::Data(result), buffer, buffsize);
        break;
    }

#ifdef _DEBUG
    printf("Address: %s\n", pn_message_get_address(msg->message));
    const char *subject = pn_message_get_subject(msg->message);
    printf("Subject: %s\n", subject ? subject : "(no subject)");
    printf("Content: %s\n", buffer);
#endif

    free(buffer);
  }
  else
  {
    result = Undefined();
  }

  return scope.Close(result);
}

void ProtonMessage::PutBody(Local<String> property,
                            Local<Value> value,
                            const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  if (value->IsString()) {
    String::Utf8Value param(value->ToString());
    std::string msgtext = std::string(*param);
    pn_message_set_format(msg->message, PN_TEXT);
    pn_message_load_text(msg->message, msgtext.c_str(), strlen(msgtext.c_str()));
    V8::AdjustAmountOfExternalAllocatedMemory(sizeof(msgtext.c_str()));
  } else if (value->IsObject()) {
    Local<Object> buffer = value->ToObject();
    char *msgdata = Buffer::Data(buffer);
    size_t msglen = Buffer::Length(buffer);
    pn_message_set_format(msg->message, PN_DATA);
    pn_message_load_data(msg->message, msgdata, msglen);
    V8::AdjustAmountOfExternalAllocatedMemory(sizeof(msgdata));
  }
}

Handle<Value> ProtonMessage::GetContentType(Local<String> property,
                                            const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());
  const char *type = pn_message_get_content_type(msg->message);

  return scope.Close(type ? String::New(type) : Null());
}

void ProtonMessage::SetContentType(Local<String> property,
                                   Local<Value> value,
                                   const AccessorInfo &info)
{
  HandleScope scope;

  ProtonMessage *msg = ObjectWrap::Unwrap<ProtonMessage>(info.Holder());

  String::Utf8Value param(value->ToString());
  std::string type = std::string(*param);

  pn_message_set_content_type(msg->message, type.c_str());
}
<|endoftext|>