<commit_before>#include "template/Parser.hpp"
#include "template/Lexer.hpp"
#include "template/Token.hpp"
#include "template/TemplateParts.hpp"
#include "template/Attributes.hpp"
#include "expression/Lexer.hpp"
#include "expression/Parser.hpp"
#include "expression/AstOp.hpp"
#include "types/Boolean.hpp"
#include "types/Nil.hpp"
#include "BuiltinFunctions.hpp"
#include "Error.hpp"
#include "Util.hpp"
#include <cassert>
#include <unordered_set>

namespace slim
{
    namespace tpl
    {
        namespace
        {
            const std::unordered_set<std::string> VOID_ELEMENTS =
            {
                "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen",
                "link", "meta", "param", "source", "track", "wbr"
            };
            const std::string DEF_TAG = "div";
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (const std::string &text_content)
        {
            handle_in_tag();
            this->text_content += text_content;
            return *this;
        }
        Parser::OutputFrame& Parser::OutputFrame::operator << (char txt_chr)
        {
            handle_in_tag();
            this->text_content += txt_chr;
            return *this;
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (std::unique_ptr<expr::ExpressionNode> &&expr)
        {
            return *this << slim::make_unique<TemplateOutputExpr>(std::move(expr));
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (std::unique_ptr<TemplatePart> &&part)
        {
            handle_in_tag();
            if (text_content.size())
            {
                contents.push_back(slim::make_unique<TemplateText>(std::move(text_content)));
                text_content.clear();
            }
            contents.push_back(std::move(part));
            return *this;
        }

        void Parser::OutputFrame::handle_in_tag()
        {
            if (in_tag())
            {
                set_in_tag(false);
                this->text_content += '>';
            }
        }

        std::unique_ptr<TemplatePart> Parser::OutputFrame::make_tpl()
        {
            if (!text_content.empty())
            {
                contents.push_back(slim::make_unique<TemplateText>(std::move(text_content)));
            }
            if (contents.size() > 1)
            {
                return slim::make_unique<TemplatePartsList>(std::move(contents));
            }
            else if (contents.size() == 1)
            {
                return std::move(contents[0]);
            }
            else return slim::make_unique<TemplateText>(std::string());
        }

        Parser::Parser(Lexer &lexer)
            : lexer(lexer)
        {}
        Parser::~Parser()
        {}

        Template Parser::parse()
        {
            OutputFrame root;
            current_token = lexer.next_indent();
            parse_lines(-1, root);
            auto root_tpl = root.make_tpl();
            return Template(std::move(root_tpl));
        }

        void Parser::parse_lines(int base_indent, OutputFrame &output)
        {
            while (current_token.type != Token::END)
            {
                assert(current_token.type == Token::INDENT);
                int my_indent = (int)current_token.str.size();
                if (my_indent <= base_indent) return;

                current_token = lexer.next_line_start();
                switch (current_token.type)
                {
                case Token::TEXT_LINE:
                    output << parse_text_line(my_indent);
                    break;
                case Token::TEXT_LINE_WITH_TRAILING_SPACE:
                    output << parse_text_line(my_indent);
                    output << ' ';
                    break;
                case Token::HTML_LINE:
                    output << '<' << parse_text_line(my_indent);
                    break;
                case Token::COMMENT_LINE:
                    parse_text_line(my_indent);
                    break;
                case Token::HTML_COMMENT_LINE:
                    output << "<!--" << parse_text_line(my_indent) << "-->";
                    break;
                case Token::NAME:
                case Token::TAG_ID:
                case Token::TAG_CLASS:
                    parse_tag(my_indent, output);
                    break;
                case Token::OUTPUT_LINE:
                    parse_code_output(output);
                    break;
                case Token::CONTROL_LINE:
                    parse_control_code(my_indent, output);
                    break;
                default: throw TemplateSyntaxError("Unexpected symbol");
                }
            }
        }

        std::string Parser::parse_text_line(int base_indent)
        {
            std::string buf;
            int leading_spaces = 0;
            while (true)
            {
                current_token = lexer.next_text_content();
                switch (current_token.type)
                {
                case Token::END: return buf;
                case Token::TEXT_CONTENT:
                    for (int i = 0; i < leading_spaces; ++i) buf += ' ';
                    buf += current_token.str;
                    current_token = lexer.next_indent();
                    if (current_indent() <= base_indent) return buf;
                    leading_spaces = current_indent() - base_indent - 2;
                    break;
                default: throw TemplateSyntaxError("Unexpected token");
                }
            }
        }

        void Parser::parse_tag(int base_indent, OutputFrame & output)
        {
            //name, id and class
            struct Attr
            {
                std::vector<std::string> static_values;
                std::vector<expr::ExpressionNodePtr> dynamic_values;
            };
            std::unordered_map<std::string, Attr> attributes;

            std::string tag_name;
            if (current_token.type == Token::NAME)
            {
                tag_name = current_token.str;
                current_token = lexer.next_tag_content();
            }
            else tag_name = DEF_TAG;
            if (current_token.type == Token::TAG_ID)
            {
                current_token = lexer.next_name();
                attributes["id"].static_values.push_back(current_token.str);
                current_token = lexer.next_tag_content();
            }
            while (current_token.type == Token::TAG_CLASS)
            {
                current_token = lexer.next_name();
                attributes["class"].static_values.push_back(current_token.str);
                current_token = lexer.next_tag_content();
            }

            //Whitespace control
            bool leading_space = false, trailing_space = false;
            switch (current_token.type)
            {
            case Token::ADD_LEADING_WHITESPACE:
                leading_space = true;
                current_token = lexer.next_tag_content();
                break;
            case Token::ADD_TRAILING_WHITESPACE:
                trailing_space = true;
                current_token = lexer.next_tag_content();
                break;
            case Token::ADD_LEADING_AND_TRAILING_WHITESPACE:
                leading_space = trailing_space = true;
                current_token = lexer.next_tag_content();
                break;
            default: break;
            }

            //Create opening tag
            if (leading_space) output << ' ';
            output << '<' << tag_name; //TODO: attributes, empty tag

            //attributes
            while (current_token.type == Token::ATTR_NAME)
            {

                expr::Lexer expr_lexer(lexer.get_pos(), lexer.get_end());
                expr::Parser expr_parser(BUILTIN_FUNCTIONS, expr_lexer); //TODO: Allow custom functions

                auto attr = current_token.str;
                auto expr = expr_parser.expression();

                lexer.set_pos(expr_parser.get_last_token().pos);

                if (auto lit = dynamic_cast<expr::Literal*>(expr.get()))
                {
                    if (lit->value == TRUE_VALUE)
                    {
                        output << ' ' << attr;
                    }
                    else if (lit->value == FALSE_VALUE || lit->value == NIL_VALUE)
                    {
                        //skip attribute
                    }
                    else
                    {
                        attributes[attr].static_values.push_back(lit->value->to_string());
                    }
                }
                else
                {
                    attributes[attr].dynamic_values.push_back(std::move(expr));
                }

                current_token = lexer.next_tag_content();
            }

            for (auto &attr : attributes)
            {
                if (attr.second.dynamic_values.empty())
                {
                    assert(attr.second.static_values.size() > 0);
                    output << attr_str(attr.first, attr.second.static_values);
                }
            }
            for (auto &attr : attributes)
            {
                if (!attr.second.dynamic_values.empty())
                {
                    output << slim::make_unique<TemplateTagAttr>(
                        attr.first,
                        std::move(attr.second.static_values),
                        std::move(attr.second.dynamic_values));
                }
            }

            //Contents
            output.set_in_tag();
            if (current_token.type == Token::TEXT_CONTENT)
            {
                output << current_token.str;
                current_token = lexer.next_indent();
            }
            else if (current_token.type == Token::EOL)
            {   //no inline content, look for indented lines after this
                current_token = lexer.next_indent();
                parse_lines(base_indent, output);
            }
            else if (current_token.type == Token::OUTPUT_LINE)
            {
                parse_code_output(output);
            }
            else if (current_token.type != Token::END)
            {
                throw TemplateSyntaxError("Unexpected token after tag line");
            }

            bool void_el = VOID_ELEMENTS.count(tag_name) > 0;
            if (output.in_tag() && void_el)
            {
                output.set_in_tag(false);
                output << "/>";
            }
            else if (!void_el) output << "</" + tag_name + ">";
            else throw TemplateSyntaxError("HTML void elements can not have content");
            if (trailing_space) output << ' ';
        }

        void Parser::parse_code_output(OutputFrame &output)
        {
            assert(current_token.type == Token::OUTPUT_LINE);
            current_token = lexer.next_whitespace_control();

            bool leading_space = false, trailing_space = false;
            switch (current_token.type)
            {
            case Token::ADD_LEADING_WHITESPACE:
                leading_space = true; break;
            case Token::ADD_TRAILING_WHITESPACE:
                trailing_space = true;  break;
            case Token::ADD_LEADING_AND_TRAILING_WHITESPACE:
                leading_space = trailing_space = true; break;
            default: break;
            }

            auto expr = parse_code_lines();

            if (leading_space) output << ' ';
            output << std::move(expr);
            if (trailing_space) output << ' ';

            current_token = lexer.next_indent();
        }

        void Parser::parse_control_code(int base_indent, OutputFrame &output)
        {
            assert(current_token.type == Token::CONTROL_LINE);

            current_token = lexer.control_code_start();
            bool have_control_line = true;
            while (have_control_line)
            {
                have_control_line = false;
                if (current_token.type == Token::IF)
                {
                    auto if_expr = parse_code_lines();
                    OutputFrame if_body;
                    std::vector<TemplateCondExpr> elsif;
                    std::unique_ptr<TemplatePart> else_body;

                    current_token = lexer.next_indent();
                    parse_lines(base_indent, if_body);

                    while (current_indent() == base_indent && lexer.try_control_line())
                    {
                        current_token = lexer.control_code_start();
                        if (current_token.type == Token::ELSIF)
                        {
                            auto expr = parse_code_lines();
                            OutputFrame frame;

                            current_token = lexer.next_indent();
                            parse_lines(base_indent, frame);

                            elsif.emplace_back(std::move(expr), frame.make_tpl());
                        }
                        else if (current_token.type == Token::ELSE)
                        {
                            current_token = lexer.next_text_content();
                            if (!current_token.str.empty())
                                throw TemplateSyntaxError("Unexpected content after 'else'");

                            OutputFrame frame;

                            current_token = lexer.next_indent();
                            parse_lines(base_indent, frame);
                            else_body = frame.make_tpl();

                            break; //'else' is last in chain
                        }
                        else //if, each, unless, etc. start a new control block in outer loop
                        {
                            have_control_line = true;
                            break;
                        }
                    }

                    output << slim::make_unique<TemplateIfExpr>(
                        TemplateCondExpr{std::move(if_expr), if_body.make_tpl()},
                        std::move(elsif),
                        std::move(else_body)
                        );
                }
                else
                {
                    throw TemplateSyntaxError("Unexpected control code start");
                }
            }
        }

        std::unique_ptr<expr::ExpressionNode> Parser::parse_code_lines()
        {
            std::string script_src;
            while (true)
            {
                current_token = lexer.next_text_content();
                if (current_token.str.empty()) throw TemplateSyntaxError("Expected expression");
                script_src += current_token.str;

                if (script_src.back() == ',')
                {
                    continue;
                }
                else if (script_src.back() == '\\')
                {
                    script_src.pop_back();
                    continue;
                }
                else break;
            }

            expr::Lexer expr_lexer(script_src);
            expr::Parser expr_parser(BUILTIN_FUNCTIONS, expr_lexer); //TODO: Allow custom functions
            auto expr = expr_parser.full_expression();

            return expr;
        }

        int Parser::current_indent()
        {
            if (current_token.type == Token::END) return -1;
            assert(current_token.type == Token::INDENT);
            return (int)current_token.str.size();
        }

    }
}
<commit_msg>Made tpl::Parser keep attributes in the order of occurrence<commit_after>#include "template/Parser.hpp"
#include "template/Lexer.hpp"
#include "template/Token.hpp"
#include "template/TemplateParts.hpp"
#include "template/Attributes.hpp"
#include "expression/Lexer.hpp"
#include "expression/Parser.hpp"
#include "expression/AstOp.hpp"
#include "types/Boolean.hpp"
#include "types/Nil.hpp"
#include "BuiltinFunctions.hpp"
#include "Error.hpp"
#include "Util.hpp"
#include <cassert>
#include <unordered_set>

namespace slim
{
    namespace tpl
    {
        namespace
        {
            const std::unordered_set<std::string> VOID_ELEMENTS =
            {
                "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen",
                "link", "meta", "param", "source", "track", "wbr"
            };
            const std::string DEF_TAG = "div";
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (const std::string &text_content)
        {
            handle_in_tag();
            this->text_content += text_content;
            return *this;
        }
        Parser::OutputFrame& Parser::OutputFrame::operator << (char txt_chr)
        {
            handle_in_tag();
            this->text_content += txt_chr;
            return *this;
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (std::unique_ptr<expr::ExpressionNode> &&expr)
        {
            return *this << slim::make_unique<TemplateOutputExpr>(std::move(expr));
        }

        Parser::OutputFrame& Parser::OutputFrame::operator << (std::unique_ptr<TemplatePart> &&part)
        {
            handle_in_tag();
            if (text_content.size())
            {
                contents.push_back(slim::make_unique<TemplateText>(std::move(text_content)));
                text_content.clear();
            }
            contents.push_back(std::move(part));
            return *this;
        }

        void Parser::OutputFrame::handle_in_tag()
        {
            if (in_tag())
            {
                set_in_tag(false);
                this->text_content += '>';
            }
        }

        std::unique_ptr<TemplatePart> Parser::OutputFrame::make_tpl()
        {
            if (!text_content.empty())
            {
                contents.push_back(slim::make_unique<TemplateText>(std::move(text_content)));
            }
            if (contents.size() > 1)
            {
                return slim::make_unique<TemplatePartsList>(std::move(contents));
            }
            else if (contents.size() == 1)
            {
                return std::move(contents[0]);
            }
            else return slim::make_unique<TemplateText>(std::string());
        }

        Parser::Parser(Lexer &lexer)
            : lexer(lexer)
        {}
        Parser::~Parser()
        {}

        Template Parser::parse()
        {
            OutputFrame root;
            current_token = lexer.next_indent();
            parse_lines(-1, root);
            auto root_tpl = root.make_tpl();
            return Template(std::move(root_tpl));
        }

        void Parser::parse_lines(int base_indent, OutputFrame &output)
        {
            while (current_token.type != Token::END)
            {
                assert(current_token.type == Token::INDENT);
                int my_indent = (int)current_token.str.size();
                if (my_indent <= base_indent) return;

                current_token = lexer.next_line_start();
                switch (current_token.type)
                {
                case Token::TEXT_LINE:
                    output << parse_text_line(my_indent);
                    break;
                case Token::TEXT_LINE_WITH_TRAILING_SPACE:
                    output << parse_text_line(my_indent);
                    output << ' ';
                    break;
                case Token::HTML_LINE:
                    output << '<' << parse_text_line(my_indent);
                    break;
                case Token::COMMENT_LINE:
                    parse_text_line(my_indent);
                    break;
                case Token::HTML_COMMENT_LINE:
                    output << "<!--" << parse_text_line(my_indent) << "-->";
                    break;
                case Token::NAME:
                case Token::TAG_ID:
                case Token::TAG_CLASS:
                    parse_tag(my_indent, output);
                    break;
                case Token::OUTPUT_LINE:
                    parse_code_output(output);
                    break;
                case Token::CONTROL_LINE:
                    parse_control_code(my_indent, output);
                    break;
                default: throw TemplateSyntaxError("Unexpected symbol");
                }
            }
        }

        std::string Parser::parse_text_line(int base_indent)
        {
            std::string buf;
            int leading_spaces = 0;
            while (true)
            {
                current_token = lexer.next_text_content();
                switch (current_token.type)
                {
                case Token::END: return buf;
                case Token::TEXT_CONTENT:
                    for (int i = 0; i < leading_spaces; ++i) buf += ' ';
                    buf += current_token.str;
                    current_token = lexer.next_indent();
                    if (current_indent() <= base_indent) return buf;
                    leading_spaces = current_indent() - base_indent - 2;
                    break;
                default: throw TemplateSyntaxError("Unexpected token");
                }
            }
        }

        void Parser::parse_tag(int base_indent, OutputFrame & output)
        {
            //name, id and class
            struct Attr
            {
                std::string name;
                std::vector<std::string> static_values;
                std::vector<expr::ExpressionNodePtr> dynamic_values;
            };
            std::vector<Attr> attributes;
            auto get_attr = [&attributes](const std::string &name) -> Attr&
            {
                for (auto &attr : attributes) if (attr.name == name) return attr;
                attributes.push_back({ name,{},{} });
                return attributes.back();
            };

            std::string tag_name;
            if (current_token.type == Token::NAME)
            {
                tag_name = current_token.str;
                current_token = lexer.next_tag_content();
            }
            else tag_name = DEF_TAG;
            if (current_token.type == Token::TAG_ID)
            {
                current_token = lexer.next_name();
                get_attr("id").static_values.push_back(current_token.str);
                current_token = lexer.next_tag_content();
            }
            while (current_token.type == Token::TAG_CLASS)
            {
                current_token = lexer.next_name();
                get_attr("class").static_values.push_back(current_token.str);
                current_token = lexer.next_tag_content();
            }

            //Whitespace control
            bool leading_space = false, trailing_space = false;
            switch (current_token.type)
            {
            case Token::ADD_LEADING_WHITESPACE:
                leading_space = true;
                current_token = lexer.next_tag_content();
                break;
            case Token::ADD_TRAILING_WHITESPACE:
                trailing_space = true;
                current_token = lexer.next_tag_content();
                break;
            case Token::ADD_LEADING_AND_TRAILING_WHITESPACE:
                leading_space = trailing_space = true;
                current_token = lexer.next_tag_content();
                break;
            default: break;
            }

            //Create opening tag
            if (leading_space) output << ' ';
            output << '<' << tag_name; //TODO: attributes, empty tag

            //attributes
            while (current_token.type == Token::ATTR_NAME)
            {

                expr::Lexer expr_lexer(lexer.get_pos(), lexer.get_end());
                expr::Parser expr_parser(BUILTIN_FUNCTIONS, expr_lexer); //TODO: Allow custom functions

                auto attr = current_token.str;
                auto expr = expr_parser.expression();

                lexer.set_pos(expr_parser.get_last_token().pos);

                if (auto lit = dynamic_cast<expr::Literal*>(expr.get()))
                {
                    if (lit->value == TRUE_VALUE)
                    {
                        output << ' ' << attr;
                    }
                    else if (lit->value == FALSE_VALUE || lit->value == NIL_VALUE)
                    {
                        //skip attribute
                    }
                    else
                    {
                        get_attr(attr).static_values.push_back(lit->value->to_string());
                    }
                }
                else
                {
                    get_attr(attr).dynamic_values.push_back(std::move(expr));
                }

                current_token = lexer.next_tag_content();
            }

            for (auto &attr : attributes)
            {
                if (attr.dynamic_values.empty())
                {
                    assert(attr.static_values.size() > 0);
                    output << attr_str(attr.name, attr.static_values);
                }
            }
            for (auto &attr : attributes)
            {
                if (!attr.dynamic_values.empty())
                {
                    output << slim::make_unique<TemplateTagAttr>(
                        attr.name,
                        std::move(attr.static_values),
                        std::move(attr.dynamic_values));
                }
            }

            //Contents
            output.set_in_tag();
            if (current_token.type == Token::TEXT_CONTENT)
            {
                output << current_token.str;
                current_token = lexer.next_indent();
            }
            else if (current_token.type == Token::EOL)
            {   //no inline content, look for indented lines after this
                current_token = lexer.next_indent();
                parse_lines(base_indent, output);
            }
            else if (current_token.type == Token::OUTPUT_LINE)
            {
                parse_code_output(output);
            }
            else if (current_token.type != Token::END)
            {
                throw TemplateSyntaxError("Unexpected token after tag line");
            }

            bool void_el = VOID_ELEMENTS.count(tag_name) > 0;
            if (output.in_tag() && void_el)
            {
                output.set_in_tag(false);
                output << "/>";
            }
            else if (!void_el) output << "</" + tag_name + ">";
            else throw TemplateSyntaxError("HTML void elements can not have content");
            if (trailing_space) output << ' ';
        }

        void Parser::parse_code_output(OutputFrame &output)
        {
            assert(current_token.type == Token::OUTPUT_LINE);
            current_token = lexer.next_whitespace_control();

            bool leading_space = false, trailing_space = false;
            switch (current_token.type)
            {
            case Token::ADD_LEADING_WHITESPACE:
                leading_space = true; break;
            case Token::ADD_TRAILING_WHITESPACE:
                trailing_space = true;  break;
            case Token::ADD_LEADING_AND_TRAILING_WHITESPACE:
                leading_space = trailing_space = true; break;
            default: break;
            }

            auto expr = parse_code_lines();

            if (leading_space) output << ' ';
            output << std::move(expr);
            if (trailing_space) output << ' ';

            current_token = lexer.next_indent();
        }

        void Parser::parse_control_code(int base_indent, OutputFrame &output)
        {
            assert(current_token.type == Token::CONTROL_LINE);

            current_token = lexer.control_code_start();
            bool have_control_line = true;
            while (have_control_line)
            {
                have_control_line = false;
                if (current_token.type == Token::IF)
                {
                    auto if_expr = parse_code_lines();
                    OutputFrame if_body;
                    std::vector<TemplateCondExpr> elsif;
                    std::unique_ptr<TemplatePart> else_body;

                    current_token = lexer.next_indent();
                    parse_lines(base_indent, if_body);

                    while (current_indent() == base_indent && lexer.try_control_line())
                    {
                        current_token = lexer.control_code_start();
                        if (current_token.type == Token::ELSIF)
                        {
                            auto expr = parse_code_lines();
                            OutputFrame frame;

                            current_token = lexer.next_indent();
                            parse_lines(base_indent, frame);

                            elsif.emplace_back(std::move(expr), frame.make_tpl());
                        }
                        else if (current_token.type == Token::ELSE)
                        {
                            current_token = lexer.next_text_content();
                            if (!current_token.str.empty())
                                throw TemplateSyntaxError("Unexpected content after 'else'");

                            OutputFrame frame;

                            current_token = lexer.next_indent();
                            parse_lines(base_indent, frame);
                            else_body = frame.make_tpl();

                            break; //'else' is last in chain
                        }
                        else //if, each, unless, etc. start a new control block in outer loop
                        {
                            have_control_line = true;
                            break;
                        }
                    }

                    output << slim::make_unique<TemplateIfExpr>(
                        TemplateCondExpr{std::move(if_expr), if_body.make_tpl()},
                        std::move(elsif),
                        std::move(else_body)
                        );
                }
                else
                {
                    throw TemplateSyntaxError("Unexpected control code start");
                }
            }
        }

        std::unique_ptr<expr::ExpressionNode> Parser::parse_code_lines()
        {
            std::string script_src;
            while (true)
            {
                current_token = lexer.next_text_content();
                if (current_token.str.empty()) throw TemplateSyntaxError("Expected expression");
                script_src += current_token.str;

                if (script_src.back() == ',')
                {
                    continue;
                }
                else if (script_src.back() == '\\')
                {
                    script_src.pop_back();
                    continue;
                }
                else break;
            }

            expr::Lexer expr_lexer(script_src);
            expr::Parser expr_parser(BUILTIN_FUNCTIONS, expr_lexer); //TODO: Allow custom functions
            auto expr = expr_parser.full_expression();

            return expr;
        }

        int Parser::current_indent()
        {
            if (current_token.type == Token::END) return -1;
            assert(current_token.type == Token::INDENT);
            return (int)current_token.str.size();
        }

    }
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Eddie N. <en@sector572.com>

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.

Author:		Eddie N. <en@sector572.com>
Date:		2017-08-25
Filename:	randomizer.cpp
Version:	1.0.0
Description:	This program takes a text file as input and reorders the lines
		in a random order outputting the results to a new file.
*/

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <map>
#include <unistd.h>

using namespace std;

void usage(char* command);

int main(int argc, char* argv[])
{
	int rtn = 0;
	int iterations = 1;
	int arg = 0;
	int error = 0;
	vector<int> lines;
	vector<int>* indexes = NULL;
	map<int, int>* usedIndexes = NULL;
	const char* fileName = NULL;
	const char* outputFileName = NULL;
	srand(time(NULL));

	while(!error && (arg = getopt(argc, argv, "f:i:o:")) != -1)
	{
		switch(arg)
		{
			case 'f':
				if(optarg)
				{
					fileName = optarg;
				}

				break;

			case 'i':
				if(optarg)
				{
					iterations = atoi(optarg);
				}

				break;

			case 'o':
				if(optarg)
				{
					outputFileName = optarg;
				}

				break;

			default:
				error = 1;
				break;
		}
	}

	if(fileName == NULL || outputFileName == NULL || iterations < 1)
	{
		error = 1;
	}

	if(error == 0)
	{
		#ifdef _DEBUG_
		cout << "Input file name:  " << fileName << endl;
		cout << "Output file name: " << outputFileName << endl;
		cout << "Iterations:       " << iterations << endl << endl;
		#endif

		ifstream inFile(fileName);

		if(!inFile)
		{
			cerr << "Unable to open the file " << fileName
				<< "." << endl;
			rtn = 1;
		}
		else
		{
			#ifdef _DEBUG_
			cout << "Processing started." << endl;
			#endif

			string line;
			int pos = 0;
			inFile.seekg(0, inFile.end);
			int length = inFile.tellg();
			inFile.seekg(0);

			while(!inFile.eof())
			{
				pos = inFile.tellg();
				if(pos < length)
				{
					lines.push_back(pos);
				}
				getline(inFile, line);
			}

			for(int i = 0; i < iterations; i++)
			{
				if(indexes != NULL)
				{
					delete indexes;
					indexes = NULL;
				}

				#ifdef _DEBUG_
				cout << "Iteration: " << (i + 1) << endl;
				#endif

				usedIndexes = new map<int, int>();
				indexes = new vector<int>();

				for(int k = 0; k < lines.size(); k++)
				{
					int index = -1;
					do
					{
						index = rand() % lines.size();
					}
					while(usedIndexes->find(index)
						 != usedIndexes->end());

					if(index > -1 && index < lines.size())
					{
						usedIndexes->operator[](index) = 0;
						indexes->push_back(index);
					}
				}

				for(int r = 0; r < lines.size(); r++)
				{
					int val1 = lines[r];
					int val2 = lines[indexes->operator[](r)];

					lines[r] = val2;
					lines[indexes->operator[](r)] = val1;
				}

				delete usedIndexes;
				usedIndexes = NULL;
			}

			inFile.clear();

			if(indexes != NULL)
			{
				ofstream outFile(outputFileName, ofstream::out);

				if(outFile)
				{
					for(vector<int>::iterator i = indexes->begin();
						i != indexes->end();
						++i)
					{
						int p = lines[*i];

						string line;
						inFile.seekg(p);
						getline(inFile, line);
						outFile << line << endl;
					}

					outFile.close();
				}

				delete indexes;
				indexes = NULL;
			}

			inFile.close();
			inFile.clear();

			#ifdef _DEBUG_
			cout << "Processing finished." << endl;
			#endif
		}
	}
	else
	{
		usage(argv[0]);
		rtn = 1;
	}

	return rtn;
}

void usage(char* command)
{
	cout << "Usage: " << endl;
	cout << command << " -f <file name> -o <output file name> "
	     << "[-i <iterations>]" << endl;
}
<commit_msg>Improved shuffle algorithm performance.<commit_after>/*
Copyright 2017 Eddie N. <en@sector572.com>

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.

Author:		Eddie N. <en@sector572.com>
Date:		2017-08-25
Filename:	randomizer.cpp
Version:	1.0.0
Description:	This program takes a text file as input and reorders the lines
		in a random order outputting the results to a new file.
*/

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <map>
#include <unistd.h>

using namespace std;

void usage(char* command);

int main(int argc, char* argv[])
{
	int rtn = 0;
	int iterations = 1;
	int arg = 0;
	int error = 0;
	vector<int> lines;
	const char* fileName = NULL;
	const char* outputFileName = NULL;
	srand(time(NULL));

	while(!error && (arg = getopt(argc, argv, "f:i:o:")) != -1)
	{
		switch(arg)
		{
			case 'f':
				if(optarg)
				{
					fileName = optarg;
				}

				break;

			case 'i':
				if(optarg)
				{
					iterations = atoi(optarg);
				}

				break;

			case 'o':
				if(optarg)
				{
					outputFileName = optarg;
				}

				break;

			default:
				error = 1;
				break;
		}
	}

	if(fileName == NULL || outputFileName == NULL || iterations < 1)
	{
		error = 1;
	}

	if(error == 0)
	{
		#ifdef _DEBUG_
		cout << "Input file name:  " << fileName << endl;
		cout << "Output file name: " << outputFileName << endl;
		cout << "Iterations:       " << iterations << endl << endl;
		#endif

		ifstream inFile(fileName);

		if(!inFile)
		{
			cerr << "Unable to open the file " << fileName
				<< "." << endl;
			rtn = 1;
		}
		else
		{
			#ifdef _DEBUG_
			cout << "Processing started." << endl;
			#endif

			string line;
			int pos = 0;
			inFile.seekg(0, inFile.end);
			int length = inFile.tellg();
			inFile.seekg(0);

			while(!inFile.eof())
			{
				pos = inFile.tellg();
				if(pos < length)
				{
					lines.push_back(pos);
				}
				getline(inFile, line);
			}

			for(int i = 0; i < iterations; i++)
			{
				#ifdef _DEBUG_
				cout << "Iteration: " << (i + 1) << endl;
				#endif

				for(int r = lines.size() - 1; r > 0; r--)
				{
					int j = rand() % r;

					if(j > -1)
					{
						int val1 = lines[r];
						int val2 = lines[j];

						lines[r] = val2;
						lines[j] = val1;
					}
				}
			}

			inFile.clear();

			ofstream outFile(outputFileName, ofstream::out);

			if(outFile)
			{
				for(int i = 0; i < lines.size(); i++)
				{
					int p = lines[i];

					string line;
					inFile.seekg(p);
					getline(inFile, line);
					outFile << line << endl;
				}

				outFile.close();
			}
		}

		inFile.close();
		inFile.clear();

		#ifdef _DEBUG_
		cout << "Processing finished." << endl;
		#endif
	}
	else
	{
		usage(argv[0]);
		rtn = 1;
	}

	return rtn;
}

void usage(char* command)
{
	cout << "Usage: " << endl;
	cout << command << " -f <file name> -o <output file name> "
	     << "[-i <iterations>]" << endl;
}
<|endoftext|>


<commit_before>#include "libtelegram/libtelegram.h"

auto main()->int {
  std::string const token("229029247:AAHfNUvcGS_ttvvulZG3Qi4NmMrjebH8F6w");     // in practice you would probably read this from config file or database
  telegram::listener listener;                                                  // create a listener which will process incoming requests
  telegram::sender sender(token);                                               // create a sender with our token for outgoing messages
  listener.set_callback_message([&](boost::property_tree::ptree const &input){  // we set a callback for receiving messages, using a lambda for convenience
    std::string  const message_text(   input.get("text", ""));                  // message components are passed in boost property tree format
    std::string  const message_sender( input.get("from.first_name", "unknown")); // we specify a default fallback in case the property isn't found
    int_fast64_t const message_chat_id(input.get<int_fast64_t>("chat.id", -1)); // the return type can be deduced from the fallback's type, or specified manually
    sender.send_message(message_chat_id, message_sender + " sent \"" + message_text + "\" to chat id " + std::to_string(message_chat_id)); // send our reply from within the callback
  });
  listener.run();                                                               // launch the listener - this call blocks until the fastcgi server drops us
  return EXIT_SUCCESS;
};
<commit_msg>replacing placeholder example token with the official one<commit_after>#include "libtelegram/libtelegram.h"

auto main()->int {
  std::string const token("bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11");      // in practice you would probably read this from config file or database
  telegram::listener listener;                                                  // create a listener which will process incoming requests
  telegram::sender sender(token);                                               // create a sender with our token for outgoing messages
  listener.set_callback_message([&](boost::property_tree::ptree const &input){  // we set a callback for receiving messages, using a lambda for convenience
    std::string  const message_text(   input.get("text", ""));                  // message components are passed in boost property tree format
    std::string  const message_sender( input.get("from.first_name", "unknown")); // we specify a default fallback in case the property isn't found
    int_fast64_t const message_chat_id(input.get<int_fast64_t>("chat.id", -1)); // the return type can be deduced from the fallback's type, or specified manually
    sender.send_message(message_chat_id, message_sender + " sent \"" + message_text + "\" to chat id " + std::to_string(message_chat_id)); // send our reply from within the callback
  });
  listener.run();                                                               // launch the listener - this call blocks until the fastcgi server drops us
  return EXIT_SUCCESS;
};
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is igor@c-base.org
//

#include "DeDistort.h"

#include "../base/XMLHelper.h"

#include <cstring>
#include <iostream>
#include <math.h>

const double sqrt3 = sqrt(3.);

using namespace std;

namespace avg {

// This transformation is based on the undistort code found at
// http://www.math.rutgers.edu/~ojanen/undistort/index.html.
//   a lot of parameters enter here, some of which can be calculated/set manually,
//   some of which need to be determined via an optimization procedure
//
//   * m_CamExtents is the size of the camera image. This is used to transform the
//     coordinates of the image so they fall in the range (-1,-1)-(1,1)
//   * m_pDistortionParams OPT see paper
//   * m_Angle corrects rotation of camera OPT
//   * m_DisplayScale convert back from standard coords to display
//   * m_DisplayOffset correct the offset of the display from the center of the table
//

DeDistort::DeDistort()
    : m_CamExtents(1,1),
      m_Angle(0.0),
      m_TrapezoidFactor(0),
      m_DisplayOffset(0,0),
      m_DisplayScale(1,1)
{
    m_DistortionParams.push_back(0);
    m_DistortionParams.push_back(0);
    m_RescaleFactor = calc_rescale();
}

DeDistort::DeDistort(const DPoint& CamExtents, const DPoint& DisplayExtents)
    : m_Angle(0.0),
      m_TrapezoidFactor(0),
      m_DisplayOffset(0,0)
{
    m_CamExtents = CamExtents;
    m_DistortionParams.push_back(0);
    m_DistortionParams.push_back(0);
    m_DisplayScale.x = DisplayExtents.x/CamExtents.x;
    m_DisplayScale.y = DisplayExtents.y/CamExtents.y;
    m_RescaleFactor = calc_rescale();
}

DeDistort::DeDistort(const DPoint &CamExtents,
            const std::vector<double>& DistortionParams,
            double Angle, double TrapezoidFactor,
            const DPoint& DisplayOffset, const DPoint& DisplayScale)
      : m_CamExtents(CamExtents),
        m_DistortionParams(DistortionParams),
        m_Angle(Angle),
        m_TrapezoidFactor(TrapezoidFactor),
        m_DisplayOffset(DisplayOffset),
        m_DisplayScale(DisplayScale)
{
    m_RescaleFactor = calc_rescale();
}

DeDistort::~DeDistort()
{
}

DRect DeDistort::getActiveBlobArea(const DPoint& DisplayExtents)
{
    DRect ActiveRect;
    ActiveRect.tl = transformScreenToBlob(DPoint(0, 0));
    ActiveRect.br = transformScreenToBlob(DPoint(DisplayExtents.x, DisplayExtents.y));
    if (ActiveRect.height() < 1) {
        double temp = ActiveRect.tl.y;
        ActiveRect.tl.y = ActiveRect.br.y;
        ActiveRect.br.y = temp;
    }
    return ActiveRect;
}

void DeDistort::load(const DPoint& CamExtents, xmlNodePtr pParentNode)
{
    m_CamExtents = CamExtents;
    xmlNodePtr curXmlChild = pParentNode->xmlChildrenNode;
    while (curXmlChild) {
        const char * pNodeName = (const char *)curXmlChild->name;
        if (!strcmp(pNodeName, "distortionparams")) {
            m_DistortionParams.clear();
            m_DistortionParams.push_back(getRequiredDoubleAttr(curXmlChild, "p2"));
            m_DistortionParams.push_back(getRequiredDoubleAttr(curXmlChild, "p3"));
        } else if (!strcmp(pNodeName, "trapezoid")) {
            m_TrapezoidFactor = getRequiredDoubleAttr(curXmlChild, "value");
        } else if (!strcmp(pNodeName, "angle")) {
            m_Angle = getRequiredDoubleAttr(curXmlChild, "value");
        } else if (!strcmp(pNodeName, "displaydisplacement")) {
            m_DisplayOffset.x = getRequiredDoubleAttr(curXmlChild, "x");
            m_DisplayOffset.y = getRequiredDoubleAttr(curXmlChild, "y");
        } else if (!strcmp(pNodeName, "displayscale")) {
            m_DisplayScale.x = getRequiredDoubleAttr(curXmlChild, "x");
            m_DisplayScale.y = getRequiredDoubleAttr(curXmlChild, "y");
        }
        curXmlChild = curXmlChild->next;
    }
    m_RescaleFactor = calc_rescale();
}

void DeDistort::save(xmlTextWriterPtr writer)
{
    int rc;
    rc = xmlTextWriterStartElement(writer, BAD_CAST "transform");
    rc = xmlTextWriterStartElement(writer, BAD_CAST "distortionparams");
    writeAttribute(writer, "p2", m_DistortionParams[0]);
    writeAttribute(writer, "p3", m_DistortionParams[1]);
    rc = xmlTextWriterEndElement(writer);
    writeSimpleXMLNode(writer, "trapezoid", m_TrapezoidFactor);
    writeSimpleXMLNode(writer, "angle", m_Angle);
    writePoint(writer, "displaydisplacement", m_DisplayOffset);
    writePoint(writer, "displayscale", m_DisplayScale);
    rc = xmlTextWriterEndElement(writer);
}

bool DeDistort::operator ==(const DeDistort& other) const
{
    return (m_CamExtents == other.m_CamExtents &&
        m_DistortionParams == other.m_DistortionParams &&
        m_Angle == other.m_Angle &&
        m_TrapezoidFactor == other.m_TrapezoidFactor &&
        m_DisplayOffset == other.m_DisplayOffset &&
        m_DisplayScale == other.m_DisplayScale &&
        m_RescaleFactor == other.m_RescaleFactor);
}

void DeDistort::dump() const
{
    cerr << "  Transform:" << endl;
    cerr << "    CamExtents: " << m_CamExtents << endl;
    cerr << "    DistortionParams: " << m_DistortionParams[0] << ", "
            << m_DistortionParams[1] << endl;
    cerr << "    Trapezoid: " << m_TrapezoidFactor << endl;
    cerr << "    Angle: " << m_Angle << endl;
    cerr << "    DisplayOffset: " << m_DisplayOffset << endl;
    cerr << "    DisplayScale: " << m_DisplayScale << endl;
}

DPoint DeDistort::transformScreenToBlob(const DPoint &pt)
{
    // scale to blob image resolution and translate 0,0 to upper left corner.
    DPoint DestPt = pt-m_DisplayOffset;
    DestPt = DPoint(DestPt.x/m_DisplayScale.x, DestPt.y/m_DisplayScale.y);
    return DestPt;
}

DPoint DeDistort::inverse_transform_point(const DPoint &pt)
{
    DPoint DestPt = pt-m_CamExtents/2;
    DestPt = DPoint(2*DestPt.x/m_CamExtents.x, 2*DestPt.y/m_CamExtents.y);
    DestPt = inv_trapezoid(m_TrapezoidFactor, DestPt);
    DestPt = rotate(DestPt, -m_Angle);
    DestPt *= m_RescaleFactor;
    DestPt = inverse_undistort(m_DistortionParams, DestPt);
    DestPt = DPoint(DestPt.x*m_CamExtents.x/2, DestPt.y*m_CamExtents.y/2);
    DestPt += m_CamExtents/2;
    return DestPt;
}

DPoint DeDistort::transformBlobToScreen(const DPoint &pt)
{
    DPoint DestPt = DPoint(m_DisplayScale.x*pt.x, m_DisplayScale.y*pt.y);
    DestPt += m_DisplayOffset;
    return DestPt;
}

DPoint DeDistort::transform_point(const DPoint &pt)
{
    DPoint DestPt = pt-m_CamExtents/2;
    DestPt = DPoint(2*DestPt.x/m_CamExtents.x, 2*DestPt.y/m_CamExtents.y);
    DestPt = undistort(m_DistortionParams, DestPt);
    DestPt /= m_RescaleFactor;
    DestPt = rotate(DestPt, m_Angle);
    DestPt = trapezoid(m_TrapezoidFactor, DestPt);
    DestPt = DPoint(DestPt.x*m_CamExtents.x/2, DestPt.y*m_CamExtents.y/2);
    DestPt += m_CamExtents/2;
    return DestPt;
}

DPoint DeDistort::inv_trapezoid(const double trapezoid_factor, const DPoint &pt)
{
    //stretch x coord
    double yn = pt.y;
    return DPoint(pt.x/(1+yn*trapezoid_factor), pt.y);
}

DPoint DeDistort::trapezoid(const double trapezoid_factor, const DPoint &pt)
{
    //stretch x coord
    double yn = pt.y;
    return DPoint(pt.x * (1 + yn*trapezoid_factor), pt.y);
}

double distort_map(const std::vector<double> &params, double r)
{
    double S = 0;
    int counter = 3;
    std::vector<double>::const_iterator v;
    for(v=params.begin(); v!=params.end(); ++v){
        S += (*v) * pow(r, counter);
        ++counter;
    }
    return r+S;
}

double DeDistort::calc_rescale()
{
    //make sure that the undistort transformation stays within the normalized box
    double scale = distort_map(m_DistortionParams, sqrt(2.0));
    return scale/sqrt(2.0);
}

double inv_distort_map(const std::vector<double> &params, double r)
{
        double r1,r2,r3,f1,f2;
        r1 = r;
        r2 = r+.001;
        f1 = distort_map(params, r1)-r;
        f2 = distort_map(params, r2)-r;
        while (fabs(f2) > 0.0001) {
            r3 = (r1*f2-r2*f1)/(f2-f1);
            r1 = r2;
            r2 = r3;
            f1 = f2;
            f2 = distort_map(params, r2)-r;
        }
        return r2;
}

#define EPSILON 0.00001
DPoint DeDistort::inverse_undistort(const std::vector<double> &params, const DPoint &pt)
{
    if ( params.empty() ) {
        return pt;
    }
    DPoint pt_norm = pt;
    double r_d = sqrt(pt_norm.x*pt_norm.x + pt_norm.y*pt_norm.y);
    double S;
    if (r_d < EPSILON) {
        S=0;
    } else {
        S = inv_distort_map(params, r_d)/r_d;
    }
    DPoint result = pt_norm*(S);
    return result;
}

DPoint DeDistort::undistort(const std::vector<double> &params, const DPoint &pt)
{
    std::vector<double>::const_iterator v = params.begin();
    if ( v == params.end() ) {
        return pt;
    }
    DPoint pt_norm = pt;
    double r_d = sqrt(pt_norm.x*pt_norm.x + pt_norm.y*pt_norm.y);
    double S;
    if (r_d < EPSILON) {
        S=0;
    } else {
        S = distort_map(params, r_d)/r_d;
    }

    DPoint result = pt_norm*(S);
    return result;
}

}
<commit_msg>Indentation fix.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is igor@c-base.org
//

#include "DeDistort.h"

#include "../base/XMLHelper.h"

#include <cstring>
#include <iostream>
#include <math.h>

const double sqrt3 = sqrt(3.);

using namespace std;

namespace avg {

// This transformation is based on the undistort code found at
// http://www.math.rutgers.edu/~ojanen/undistort/index.html.
//   a lot of parameters enter here, some of which can be calculated/set manually,
//   some of which need to be determined via an optimization procedure
//
//   * m_CamExtents is the size of the camera image. This is used to transform the
//     coordinates of the image so they fall in the range (-1,-1)-(1,1)
//   * m_pDistortionParams OPT see paper
//   * m_Angle corrects rotation of camera OPT
//   * m_DisplayScale convert back from standard coords to display
//   * m_DisplayOffset correct the offset of the display from the center of the table
//

DeDistort::DeDistort()
    : m_CamExtents(1,1),
      m_Angle(0.0),
      m_TrapezoidFactor(0),
      m_DisplayOffset(0,0),
      m_DisplayScale(1,1)
{
    m_DistortionParams.push_back(0);
    m_DistortionParams.push_back(0);
    m_RescaleFactor = calc_rescale();
}

DeDistort::DeDistort(const DPoint& CamExtents, const DPoint& DisplayExtents)
    : m_Angle(0.0),
      m_TrapezoidFactor(0),
      m_DisplayOffset(0,0)
{
    m_CamExtents = CamExtents;
    m_DistortionParams.push_back(0);
    m_DistortionParams.push_back(0);
    m_DisplayScale.x = DisplayExtents.x/CamExtents.x;
    m_DisplayScale.y = DisplayExtents.y/CamExtents.y;
    m_RescaleFactor = calc_rescale();
}

DeDistort::DeDistort(const DPoint &CamExtents,
        const std::vector<double>& DistortionParams,
        double Angle, double TrapezoidFactor,
        const DPoint& DisplayOffset, const DPoint& DisplayScale)
    : m_CamExtents(CamExtents),
      m_DistortionParams(DistortionParams),
      m_Angle(Angle),
      m_TrapezoidFactor(TrapezoidFactor),
      m_DisplayOffset(DisplayOffset),
      m_DisplayScale(DisplayScale)
{
    m_RescaleFactor = calc_rescale();
}

DeDistort::~DeDistort()
{
}

DRect DeDistort::getActiveBlobArea(const DPoint& DisplayExtents)
{
    DRect ActiveRect;
    ActiveRect.tl = transformScreenToBlob(DPoint(0, 0));
    ActiveRect.br = transformScreenToBlob(DPoint(DisplayExtents.x, DisplayExtents.y));
    if (ActiveRect.height() < 1) {
        double temp = ActiveRect.tl.y;
        ActiveRect.tl.y = ActiveRect.br.y;
        ActiveRect.br.y = temp;
    }
    return ActiveRect;
}

void DeDistort::load(const DPoint& CamExtents, xmlNodePtr pParentNode)
{
    m_CamExtents = CamExtents;
    xmlNodePtr curXmlChild = pParentNode->xmlChildrenNode;
    while (curXmlChild) {
        const char * pNodeName = (const char *)curXmlChild->name;
        if (!strcmp(pNodeName, "distortionparams")) {
            m_DistortionParams.clear();
            m_DistortionParams.push_back(getRequiredDoubleAttr(curXmlChild, "p2"));
            m_DistortionParams.push_back(getRequiredDoubleAttr(curXmlChild, "p3"));
        } else if (!strcmp(pNodeName, "trapezoid")) {
            m_TrapezoidFactor = getRequiredDoubleAttr(curXmlChild, "value");
        } else if (!strcmp(pNodeName, "angle")) {
            m_Angle = getRequiredDoubleAttr(curXmlChild, "value");
        } else if (!strcmp(pNodeName, "displaydisplacement")) {
            m_DisplayOffset.x = getRequiredDoubleAttr(curXmlChild, "x");
            m_DisplayOffset.y = getRequiredDoubleAttr(curXmlChild, "y");
        } else if (!strcmp(pNodeName, "displayscale")) {
            m_DisplayScale.x = getRequiredDoubleAttr(curXmlChild, "x");
            m_DisplayScale.y = getRequiredDoubleAttr(curXmlChild, "y");
        }
        curXmlChild = curXmlChild->next;
    }
    m_RescaleFactor = calc_rescale();
}

void DeDistort::save(xmlTextWriterPtr writer)
{
    int rc;
    rc = xmlTextWriterStartElement(writer, BAD_CAST "transform");
    rc = xmlTextWriterStartElement(writer, BAD_CAST "distortionparams");
    writeAttribute(writer, "p2", m_DistortionParams[0]);
    writeAttribute(writer, "p3", m_DistortionParams[1]);
    rc = xmlTextWriterEndElement(writer);
    writeSimpleXMLNode(writer, "trapezoid", m_TrapezoidFactor);
    writeSimpleXMLNode(writer, "angle", m_Angle);
    writePoint(writer, "displaydisplacement", m_DisplayOffset);
    writePoint(writer, "displayscale", m_DisplayScale);
    rc = xmlTextWriterEndElement(writer);
}

bool DeDistort::operator ==(const DeDistort& other) const
{
    return (m_CamExtents == other.m_CamExtents &&
        m_DistortionParams == other.m_DistortionParams &&
        m_Angle == other.m_Angle &&
        m_TrapezoidFactor == other.m_TrapezoidFactor &&
        m_DisplayOffset == other.m_DisplayOffset &&
        m_DisplayScale == other.m_DisplayScale &&
        m_RescaleFactor == other.m_RescaleFactor);
}

void DeDistort::dump() const
{
    cerr << "  Transform:" << endl;
    cerr << "    CamExtents: " << m_CamExtents << endl;
    cerr << "    DistortionParams: " << m_DistortionParams[0] << ", "
            << m_DistortionParams[1] << endl;
    cerr << "    Trapezoid: " << m_TrapezoidFactor << endl;
    cerr << "    Angle: " << m_Angle << endl;
    cerr << "    DisplayOffset: " << m_DisplayOffset << endl;
    cerr << "    DisplayScale: " << m_DisplayScale << endl;
}

DPoint DeDistort::transformScreenToBlob(const DPoint &pt)
{
    // scale to blob image resolution and translate 0,0 to upper left corner.
    DPoint DestPt = pt-m_DisplayOffset;
    DestPt = DPoint(DestPt.x/m_DisplayScale.x, DestPt.y/m_DisplayScale.y);
    return DestPt;
}

DPoint DeDistort::inverse_transform_point(const DPoint &pt)
{
    DPoint DestPt = pt-m_CamExtents/2;
    DestPt = DPoint(2*DestPt.x/m_CamExtents.x, 2*DestPt.y/m_CamExtents.y);
    DestPt = inv_trapezoid(m_TrapezoidFactor, DestPt);
    DestPt = rotate(DestPt, -m_Angle);
    DestPt *= m_RescaleFactor;
    DestPt = inverse_undistort(m_DistortionParams, DestPt);
    DestPt = DPoint(DestPt.x*m_CamExtents.x/2, DestPt.y*m_CamExtents.y/2);
    DestPt += m_CamExtents/2;
    return DestPt;
}

DPoint DeDistort::transformBlobToScreen(const DPoint &pt)
{
    DPoint DestPt = DPoint(m_DisplayScale.x*pt.x, m_DisplayScale.y*pt.y);
    DestPt += m_DisplayOffset;
    return DestPt;
}

DPoint DeDistort::transform_point(const DPoint &pt)
{
    DPoint DestPt = pt-m_CamExtents/2;
    DestPt = DPoint(2*DestPt.x/m_CamExtents.x, 2*DestPt.y/m_CamExtents.y);
    DestPt = undistort(m_DistortionParams, DestPt);
    DestPt /= m_RescaleFactor;
    DestPt = rotate(DestPt, m_Angle);
    DestPt = trapezoid(m_TrapezoidFactor, DestPt);
    DestPt = DPoint(DestPt.x*m_CamExtents.x/2, DestPt.y*m_CamExtents.y/2);
    DestPt += m_CamExtents/2;
    return DestPt;
}

DPoint DeDistort::inv_trapezoid(const double trapezoid_factor, const DPoint &pt)
{
    //stretch x coord
    double yn = pt.y;
    return DPoint(pt.x/(1+yn*trapezoid_factor), pt.y);
}

DPoint DeDistort::trapezoid(const double trapezoid_factor, const DPoint &pt)
{
    //stretch x coord
    double yn = pt.y;
    return DPoint(pt.x * (1 + yn*trapezoid_factor), pt.y);
}

double distort_map(const std::vector<double> &params, double r)
{
    double S = 0;
    int counter = 3;
    std::vector<double>::const_iterator v;
    for(v=params.begin(); v!=params.end(); ++v){
        S += (*v) * pow(r, counter);
        ++counter;
    }
    return r+S;
}

double DeDistort::calc_rescale()
{
    //make sure that the undistort transformation stays within the normalized box
    double scale = distort_map(m_DistortionParams, sqrt(2.0));
    return scale/sqrt(2.0);
}

double inv_distort_map(const std::vector<double> &params, double r)
{
        double r1,r2,r3,f1,f2;
        r1 = r;
        r2 = r+.001;
        f1 = distort_map(params, r1)-r;
        f2 = distort_map(params, r2)-r;
        while (fabs(f2) > 0.0001) {
            r3 = (r1*f2-r2*f1)/(f2-f1);
            r1 = r2;
            r2 = r3;
            f1 = f2;
            f2 = distort_map(params, r2)-r;
        }
        return r2;
}

#define EPSILON 0.00001
DPoint DeDistort::inverse_undistort(const std::vector<double> &params, const DPoint &pt)
{
    if ( params.empty() ) {
        return pt;
    }
    DPoint pt_norm = pt;
    double r_d = sqrt(pt_norm.x*pt_norm.x + pt_norm.y*pt_norm.y);
    double S;
    if (r_d < EPSILON) {
        S=0;
    } else {
        S = inv_distort_map(params, r_d)/r_d;
    }
    DPoint result = pt_norm*(S);
    return result;
}

DPoint DeDistort::undistort(const std::vector<double> &params, const DPoint &pt)
{
    std::vector<double>::const_iterator v = params.begin();
    if ( v == params.end() ) {
        return pt;
    }
    DPoint pt_norm = pt;
    double r_d = sqrt(pt_norm.x*pt_norm.x + pt_norm.y*pt_norm.y);
    double S;
    if (r_d < EPSILON) {
        S=0;
    } else {
        S = distort_map(params, r_d)/r_d;
    }

    DPoint result = pt_norm*(S);
    return result;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/detail/AtFork.h>

#include <list>
#include <mutex>

#include <folly/ScopeGuard.h>
#include <folly/lang/Exception.h>
#include <folly/portability/PThread.h>
#include <folly/synchronization/SanitizeThread.h>

namespace folly {

namespace detail {

namespace {

#if !FOLLY_MOBILE && !defined(__APPLE__) && !defined(_MSC_VER)
#define FOLLY_ATFORK_USE_FOLLY_TLS 1
#else
#define FOLLY_ATFORK_USE_FOLLY_TLS 0
#endif

template <bool enabled = FOLLY_ATFORK_USE_FOLLY_TLS>
struct SkipAtForkHandlers;

template <>
struct SkipAtForkHandlers<false> {
  static bool available() { return false; }

  static bool get() { return false; }

  [[noreturn]] static void set(bool) { std::terminate(); }
};

#if FOLLY_ATFORK_USE_FOLLY_TLS
template <>
struct SkipAtForkHandlers<true> {
  static bool available() { return true; }

  static bool get() { return value_; }

  static void set(bool value) { value_ = value; }

 private:
  static thread_local bool value_;
};
thread_local bool SkipAtForkHandlers<true>::value_{false};
#endif

struct AtForkTask {
  void const* handle;
  folly::Function<bool()> prepare;
  folly::Function<void()> parent;
  folly::Function<void()> child;
};

class AtForkList {
 public:
  static AtForkList& instance() {
    static auto instance = new AtForkList();
    return *instance;
  }

  static void prepare() noexcept {
    if (SkipAtForkHandlers<>::get()) {
      return;
    }
    instance().tasksLock.lock();
    while (true) {
      auto& tasks = instance().tasks;
      auto task = tasks.rbegin();
      for (; task != tasks.rend(); ++task) {
        if (!task->prepare()) {
          break;
        }
      }
      if (task == tasks.rend()) {
        return;
      }
      for (auto untask = tasks.rbegin(); untask != task; ++untask) {
        untask->parent();
      }
    }
  }

  static void parent() noexcept {
    if (SkipAtForkHandlers<>::get()) {
      return;
    }
    auto& tasks = instance().tasks;
    for (auto& task : tasks) {
      task.parent();
    }
    instance().tasksLock.unlock();
  }

  static void child() noexcept {
    if (SkipAtForkHandlers<>::get()) {
      return;
    }
    // if we fork a multithreaded process
    // some of the TSAN mutexes might be locked
    // so we just enable ignores for everything
    // while handling the child callbacks
    // This might still be an issue if we do not exec right away
    annotate_ignore_thread_sanitizer_guard g(__FILE__, __LINE__);

    auto& tasks = instance().tasks;
    for (auto& task : tasks) {
      task.child();
    }
    instance().tasksLock.unlock();
  }

  std::mutex tasksLock;
  std::list<AtForkTask> tasks;

 private:
  AtForkList() {
#if FOLLY_HAVE_PTHREAD_ATFORK
    int ret = pthread_atfork(
        &AtForkList::prepare, &AtForkList::parent, &AtForkList::child);
    if (ret != 0) {
      throw_exception<std::system_error>(
          ret, std::generic_category(), "pthread_atfork failed");
    }
#elif !__ANDROID__ && !defined(_MSC_VER)
// pthread_atfork is not part of the Android NDK at least as of n9d. If
// something is trying to call native fork() directly at all with Android's
// process management model, this is probably the least of the problems.
//
// But otherwise, this is a problem.
#warning pthread_atfork unavailable
#endif
  }
};
} // namespace

void AtFork::init() {
  AtForkList::instance();
}

void AtFork::registerHandler(
    void const* handle,
    folly::Function<bool()> prepare,
    folly::Function<void()> parent,
    folly::Function<void()> child) {
  std::lock_guard<std::mutex> lg(AtForkList::instance().tasksLock);
  AtForkList::instance().tasks.push_back(
      {handle, std::move(prepare), std::move(parent), std::move(child)});
}

void AtFork::unregisterHandler(void const* handle) {
  if (!handle) {
    return;
  }
  auto& list = AtForkList::instance();
  std::lock_guard<std::mutex> lg(list.tasksLock);
  for (auto it = list.tasks.begin(); it != list.tasks.end(); ++it) {
    if (it->handle == handle) {
      list.tasks.erase(it);
      return;
    }
  }
}

pid_t AtFork::forkInstrumented(fork_t forkFn) {
  if (SkipAtForkHandlers<>::available()) {
    AtForkList::prepare();
    SkipAtForkHandlers<>::set(true);
    auto ret = forkFn();
    SkipAtForkHandlers<>::set(false);
    if (ret) {
      AtForkList::parent();
    } else {
      AtForkList::child();
    }
    return ret;
  } else {
    return forkFn();
  }
}
} // namespace detail
} // namespace folly
<commit_msg>assume thread_local in AtFork<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/detail/AtFork.h>

#include <list>
#include <mutex>

#include <folly/ScopeGuard.h>
#include <folly/lang/Exception.h>
#include <folly/portability/PThread.h>
#include <folly/synchronization/SanitizeThread.h>

namespace folly {

namespace detail {

namespace {

struct SkipAtForkHandlers {
  static thread_local bool value;

  struct Guard {
    bool saved = value;
    Guard() { value = true; }
    ~Guard() { value = saved; }
  };
};
thread_local bool SkipAtForkHandlers::value;

struct AtForkTask {
  void const* handle;
  folly::Function<bool()> prepare;
  folly::Function<void()> parent;
  folly::Function<void()> child;
};

class AtForkList {
 public:
  static AtForkList& instance() {
    static auto instance = new AtForkList();
    return *instance;
  }

  static void prepare() noexcept {
    if (SkipAtForkHandlers::value) {
      return;
    }
    instance().tasksLock.lock();
    while (true) {
      auto& tasks = instance().tasks;
      auto task = tasks.rbegin();
      for (; task != tasks.rend(); ++task) {
        if (!task->prepare()) {
          break;
        }
      }
      if (task == tasks.rend()) {
        return;
      }
      for (auto untask = tasks.rbegin(); untask != task; ++untask) {
        untask->parent();
      }
    }
  }

  static void parent() noexcept {
    if (SkipAtForkHandlers::value) {
      return;
    }
    auto& tasks = instance().tasks;
    for (auto& task : tasks) {
      task.parent();
    }
    instance().tasksLock.unlock();
  }

  static void child() noexcept {
    if (SkipAtForkHandlers::value) {
      return;
    }
    // if we fork a multithreaded process
    // some of the TSAN mutexes might be locked
    // so we just enable ignores for everything
    // while handling the child callbacks
    // This might still be an issue if we do not exec right away
    annotate_ignore_thread_sanitizer_guard g(__FILE__, __LINE__);

    auto& tasks = instance().tasks;
    for (auto& task : tasks) {
      task.child();
    }
    instance().tasksLock.unlock();
  }

  std::mutex tasksLock;
  std::list<AtForkTask> tasks;

 private:
  AtForkList() {
#if FOLLY_HAVE_PTHREAD_ATFORK
    int ret = pthread_atfork(
        &AtForkList::prepare, &AtForkList::parent, &AtForkList::child);
    if (ret != 0) {
      throw_exception<std::system_error>(
          ret, std::generic_category(), "pthread_atfork failed");
    }
#elif !__ANDROID__ && !defined(_MSC_VER)
// pthread_atfork is not part of the Android NDK at least as of n9d. If
// something is trying to call native fork() directly at all with Android's
// process management model, this is probably the least of the problems.
//
// But otherwise, this is a problem.
#warning pthread_atfork unavailable
#endif
  }
};
} // namespace

void AtFork::init() {
  AtForkList::instance();
}

void AtFork::registerHandler(
    void const* handle,
    folly::Function<bool()> prepare,
    folly::Function<void()> parent,
    folly::Function<void()> child) {
  std::lock_guard<std::mutex> lg(AtForkList::instance().tasksLock);
  AtForkList::instance().tasks.push_back(
      {handle, std::move(prepare), std::move(parent), std::move(child)});
}

void AtFork::unregisterHandler(void const* handle) {
  if (!handle) {
    return;
  }
  auto& list = AtForkList::instance();
  std::lock_guard<std::mutex> lg(list.tasksLock);
  for (auto it = list.tasks.begin(); it != list.tasks.end(); ++it) {
    if (it->handle == handle) {
      list.tasks.erase(it);
      return;
    }
  }
}

pid_t AtFork::forkInstrumented(fork_t forkFn) {
  AtForkList::prepare();
  auto ret = [&] {
    SkipAtForkHandlers::Guard guard;
    return forkFn();
  }();
  if (ret) {
    AtForkList::parent();
  } else {
    AtForkList::child();
  }
  return ret;
}
} // namespace detail
} // namespace folly
<|endoftext|>


<commit_before>#include <chrono>
#include <iostream>

#include <cuda_runtime.h>
#include "cublas_v2.h"

#include "rnn.h"
#include "util.h"

RNNParameters load_params(ModelSpec spec) {
  float *U = make_rand_matrix(spec.model_dim, spec.model_dim);
  float *W = make_rand_matrix(spec.model_dim, spec.word_embedding_dim);
  float *b = make_rand_matrix(spec.model_dim, 1);

  RNNParameters ret = {U, W, b};
  return ret;
}

void destroy_params(RNNParameters params) {
  cudaFree(params.U);
  cudaFree(params.W);
  cudaFree(params.b);
}

int main() {
  ModelSpec spec = {10, 10, 1, 10, 30, 10};//{300, 300, (size_t) atoi(getenv("BATCH_SIZE")), 10, 30, 300};
  RNNParameters params = load_params(spec);

  cublasHandle_t handle;
  cublasStatus_t stat = cublasCreate(&handle);
  if (stat != CUBLAS_STATUS_SUCCESS) {
    cout << "CUBLAS initialization failed" << endl;
    return 1;
  }

  RNN rnn(spec, params, handle);

  // Set model inputs.
  cout << "X:" << endl;
  fill_rand_matrix(rnn.X, spec.model_dim, spec.batch_size * spec.seq_length);

  auto time_elapsed = chrono::microseconds::zero();
  int n_batches = 50;
  for (int t = 0; t < n_batches; t++) {
    auto start = chrono::high_resolution_clock::now();
    rnn.forward();
    auto end = chrono::high_resolution_clock::now();
    time_elapsed += chrono::duration_cast<chrono::microseconds>(end - start);
  }

  // Print the final representation.
  cout << "Output:" << endl;
  print_device_matrix(rnn.output, spec.model_dim, spec.batch_size);

  cout << "Total time elapsed: " << time_elapsed.count() << endl;

  destroy_params(params);
}
<commit_msg>Use full model size in rnntest<commit_after>#include <chrono>
#include <iostream>

#include <cuda_runtime.h>
#include "cublas_v2.h"

#include "rnn.h"
#include "util.h"

RNNParameters load_params(ModelSpec spec) {
  float *U = make_rand_matrix(spec.model_dim, spec.model_dim);
  float *W = make_rand_matrix(spec.model_dim, spec.word_embedding_dim);
  float *b = make_rand_matrix(spec.model_dim, 1);

  RNNParameters ret = {U, W, b};
  return ret;
}

void destroy_params(RNNParameters params) {
  cudaFree(params.U);
  cudaFree(params.W);
  cudaFree(params.b);
}

int main() {
  ModelSpec spec = {300, 300, (size_t) atoi(getenv("BATCH_SIZE")), 10, 30, 300};
  RNNParameters params = load_params(spec);

  cublasHandle_t handle;
  cublasStatus_t stat = cublasCreate(&handle);
  if (stat != CUBLAS_STATUS_SUCCESS) {
    cout << "CUBLAS initialization failed" << endl;
    return 1;
  }

  RNN rnn(spec, params, handle);

  // Set model inputs.
  cout << "X:" << endl;
  fill_rand_matrix(rnn.X, spec.model_dim, spec.batch_size * spec.seq_length);

  auto time_elapsed = chrono::microseconds::zero();
  int n_batches = 50;
  for (int t = 0; t < n_batches; t++) {
    auto start = chrono::high_resolution_clock::now();
    rnn.forward();
    auto end = chrono::high_resolution_clock::now();
    time_elapsed += chrono::duration_cast<chrono::microseconds>(end - start);
  }

  // Print the final representation.
  cout << "Output:" << endl;
  print_device_matrix(rnn.output, spec.model_dim, spec.batch_size);

  cout << "Total time elapsed: " << time_elapsed.count() << endl;

  destroy_params(params);
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, NVIDIA CORPORATION. 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 NVIDIA CORPORATION 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 ``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.

#include "src/clients/c++/request.h"

#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

namespace ni = nvidia::inferenceserver;
namespace nic = nvidia::inferenceserver::client;

#define FAIL_IF_ERR(X, MSG)                                        \
  {                                                                \
    nic::Error err = (X);                                          \
    if (!err.IsOk()) {                                             \
      std::cerr << "error: " << (MSG) << ": " << err << std::endl; \
      exit(1);                                                     \
    }                                                              \
  }

namespace {

void
Postprocess(
    const std::map<std::string, std::unique_ptr<nic::InferContext::Result>>&
        results,
    const std::vector<std::string>& filenames, const size_t batch_size)
{
  if (results.size() != 1) {
    std::cerr << "expected 1 result, got " << results.size() << std::endl;
    exit(1);
  }

  const std::unique_ptr<nic::InferContext::Result>& result =
      results.begin()->second;

  for (size_t b = 0; b < batch_size; ++b) {
    size_t cnt = 0;
    nic::Error err = result->GetClassCount(b, &cnt);
    if (!err.IsOk()) {
      std::cerr << "failed reading class count for batch " << b << ": " << err
                << std::endl;
      exit(1);
    }

    std::cout << "Image '" << filenames[b] << "':" << std::endl;

    for (size_t c = 0; c < cnt; ++c) {
      nic::InferContext::Result::ClassResult cls;
      nic::Error err = result->GetClassAtCursor(b, &cls);
      if (!err.IsOk()) {
        std::cerr << "failed reading class for batch " << b << ": " << err
                  << std::endl;
        exit(1);
      }

      std::cout << "    " << cls.idx << " (" << cls.label << ") = " << cls.value
                << std::endl;
    }
  }
}

void
Usage(char** argv, const std::string& msg = std::string())
{
  if (!msg.empty()) {
    std::cerr << "error: " << msg << std::endl;
  }

  std::cerr << "Usage: " << argv[0] << " [options] <image filename / image folder>" << std::endl;
  std::cerr << "\t-v" << std::endl;
  std::cerr << "\t-c <topk>" << std::endl;
  std::cerr << "\t-i <Protocol used to communicate with inference service>"
            << std::endl;
  std::cerr << "\t-u <URL for inference service>" << std::endl;
  std::cerr << std::endl;
  std::cerr << "For -c, the <topk> classes will be returned, default is 1."
            << std::endl;
  std::cerr
      << "For -i, available protocols are 'grpc' and 'http'. Default is 'http."
      << std::endl;

  exit(1);
}

}  // namespace

int
main(int argc, char** argv)
{
  bool verbose = false;
  std::string url("localhost:8000");
  std::string protocol = "http";
  size_t topk = 1;

  // Parse commandline...
  int opt;
  while ((opt = getopt(argc, argv, "vi:u:p:c:")) != -1) {
    switch (opt) {
      case 'v':
        verbose = true;
        break;
      case 'i':
        protocol = optarg;
        break;
      case 'u':
        url = optarg;
        break;
      case 'c':
        topk = std::atoi(optarg);
        break;
      case '?':
        Usage(argv);
        break;
    }
  }

  if (topk <= 0) {
    Usage(argv, "topk must be > 0");
  }

  nic::Error err;

  // The ensemble model takes 1 input tensor with shape [ 1 ] and STRING
  // data type and returns 1 output tensor as top k (see '-c' flag)
  // classification result of the input.
  std::string model_name = "preprocess_resnet50_ensemble";

  // Create the inference context for the model.
  std::unique_ptr<nic::InferContext> ctx;
  if (protocol == "http") {
    err = nic::InferHttpContext::Create(
        &ctx, url, model_name, -1 /* model_version */, verbose);
  } else if (protocol == "grpc") {
    err = nic::InferGrpcContext::Create(
        &ctx, url, model_name, -1 /* model_version */, verbose);
  } else {
    Usage(argv, "unknown protocol '" + protocol + "'");
  }
  if (optind >= argc) {
    Usage(argv, "image file or image folder must be specified");
  }

  if (!err.IsOk()) {
    std::cerr << "error: unable to create inference context: " << err
              << std::endl;
    exit(1);
  }

  // Obtain a list of the image names to be processed
  std::vector<std::string> image_filenames;

  struct stat name_stat;
  if (stat(argv[optind], &name_stat) != 0) {
    std::cerr << "Failed to find '" << std::string(argv[optind])
              << "': " << strerror(errno) << std::endl;
    exit(1);
  }

  if (name_stat.st_mode & S_IFDIR) {
    const std::string dirname = argv[optind];
    DIR* dir_ptr = opendir(dirname.c_str());
    struct dirent* d_ptr;
    while ((d_ptr = readdir(dir_ptr)) != NULL) {
      const std::string filename = d_ptr->d_name;
      if ((filename != ".") && (filename != "..")) {
        image_filenames.push_back(dirname + "/" + filename);
      }
    }
    closedir(dir_ptr);
  } else {
    image_filenames.push_back(argv[optind]);
  }

  // Sort the filenames so that we always visit them in the same order
  // (readdir does not guarantee any particular order).
  std::sort(image_filenames.begin(), image_filenames.end());

  // Read the raw image as string
  std::vector<std::vector<std::string>> images;
  for (const auto& fn : image_filenames) {
    images.emplace_back();
    auto& image_str = images.back();
    std::ifstream file(fn);
    file >> std::noskipws;
    image_str.emplace_back((std::istreambuf_iterator<char>(file)),
                  std::istreambuf_iterator<char>());
    if (image_str.back().empty()) {
      std::cerr << "error: unable to read image file " << fn << std::endl;
      exit(1);
    }
  }

  // this client only send one request for simplicity. So the maximum number
  // of the images to be processed is limited by the maximum batch size
  uint64_t batch_size = ctx->MaxBatchSize();
  if (images.size() > batch_size) {
    std::cerr << "The number of images exceeds maximum batch size, only the"
              << " first " << batch_size << " images, sorted by name"
              << " alphabetically, will be processed" << std::endl;
  }
  batch_size = (images.size() < batch_size) ? images.size() : batch_size;

  // Set the context options to do 1 request. Also request
  // the return type of the result.
  std::unique_ptr<nic::InferContext::Options> options;
  FAIL_IF_ERR(
      nic::InferContext::Options::Create(&options),
      "unable to create inference options");

  options->SetBatchSize(batch_size);
  for (const auto& output : ctx->Outputs()) {
    options->AddClassResult(output, topk);
  }

  FAIL_IF_ERR(ctx->SetRunOptions(*options), "unable to set inference options");

  // Initialize the inputs with the data.
  std::shared_ptr<nic::InferContext::Input> input;
  FAIL_IF_ERR(ctx->GetInput("INPUT", &input), "unable to get INPUT");

  FAIL_IF_ERR(input->Reset(), "unable to reset INPUT");

  for (size_t i = 0; i < batch_size; i++) {
    FAIL_IF_ERR(
        input->SetFromString(images[i]), "unable to set data for INPUT");
  }

  // Send inference request to the inference server.
  std::map<std::string, std::unique_ptr<nic::InferContext::Result>> results;
  FAIL_IF_ERR(ctx->Run(&results), "unable to run model");

  // We expect there to be 1 result. The result may be batched.
  if (results.size() != 1) {
    std::cerr << "error: expected 1 results, got " << results.size()
              << std::endl;
  }

  // Print classification results
  for (size_t i = 0; i < batch_size; i++) {
    // Read the output values if we are performing classification.
    Postprocess(results, image_filenames, batch_size);
  }

  return 0;
}
<commit_msg>Format<commit_after>// Copyright (c) 2019, NVIDIA CORPORATION. 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 NVIDIA CORPORATION 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 ``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.

#include "src/clients/c++/request.h"

#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

namespace ni = nvidia::inferenceserver;
namespace nic = nvidia::inferenceserver::client;

#define FAIL_IF_ERR(X, MSG)                                        \
  {                                                                \
    nic::Error err = (X);                                          \
    if (!err.IsOk()) {                                             \
      std::cerr << "error: " << (MSG) << ": " << err << std::endl; \
      exit(1);                                                     \
    }                                                              \
  }

namespace {

void
Postprocess(
    const std::map<std::string, std::unique_ptr<nic::InferContext::Result>>&
        results,
    const std::vector<std::string>& filenames, const size_t batch_size)
{
  if (results.size() != 1) {
    std::cerr << "expected 1 result, got " << results.size() << std::endl;
    exit(1);
  }

  const std::unique_ptr<nic::InferContext::Result>& result =
      results.begin()->second;

  for (size_t b = 0; b < batch_size; ++b) {
    size_t cnt = 0;
    nic::Error err = result->GetClassCount(b, &cnt);
    if (!err.IsOk()) {
      std::cerr << "failed reading class count for batch " << b << ": " << err
                << std::endl;
      exit(1);
    }

    std::cout << "Image '" << filenames[b] << "':" << std::endl;

    for (size_t c = 0; c < cnt; ++c) {
      nic::InferContext::Result::ClassResult cls;
      nic::Error err = result->GetClassAtCursor(b, &cls);
      if (!err.IsOk()) {
        std::cerr << "failed reading class for batch " << b << ": " << err
                  << std::endl;
        exit(1);
      }

      std::cout << "    " << cls.idx << " (" << cls.label << ") = " << cls.value
                << std::endl;
    }
  }
}

void
Usage(char** argv, const std::string& msg = std::string())
{
  if (!msg.empty()) {
    std::cerr << "error: " << msg << std::endl;
  }

  std::cerr << "Usage: " << argv[0]
            << " [options] <image filename / image folder>" << std::endl;
  std::cerr << "\t-v" << std::endl;
  std::cerr << "\t-c <topk>" << std::endl;
  std::cerr << "\t-i <Protocol used to communicate with inference service>"
            << std::endl;
  std::cerr << "\t-u <URL for inference service>" << std::endl;
  std::cerr << std::endl;
  std::cerr << "For -c, the <topk> classes will be returned, default is 1."
            << std::endl;
  std::cerr
      << "For -i, available protocols are 'grpc' and 'http'. Default is 'http."
      << std::endl;

  exit(1);
}

}  // namespace

int
main(int argc, char** argv)
{
  bool verbose = false;
  std::string url("localhost:8000");
  std::string protocol = "http";
  size_t topk = 1;

  // Parse commandline...
  int opt;
  while ((opt = getopt(argc, argv, "vi:u:p:c:")) != -1) {
    switch (opt) {
      case 'v':
        verbose = true;
        break;
      case 'i':
        protocol = optarg;
        break;
      case 'u':
        url = optarg;
        break;
      case 'c':
        topk = std::atoi(optarg);
        break;
      case '?':
        Usage(argv);
        break;
    }
  }

  if (topk <= 0) {
    Usage(argv, "topk must be > 0");
  }

  nic::Error err;

  // The ensemble model takes 1 input tensor with shape [ 1 ] and STRING
  // data type and returns 1 output tensor as top k (see '-c' flag)
  // classification result of the input.
  std::string model_name = "preprocess_resnet50_ensemble";

  // Create the inference context for the model.
  std::unique_ptr<nic::InferContext> ctx;
  if (protocol == "http") {
    err = nic::InferHttpContext::Create(
        &ctx, url, model_name, -1 /* model_version */, verbose);
  } else if (protocol == "grpc") {
    err = nic::InferGrpcContext::Create(
        &ctx, url, model_name, -1 /* model_version */, verbose);
  } else {
    Usage(argv, "unknown protocol '" + protocol + "'");
  }
  if (optind >= argc) {
    Usage(argv, "image file or image folder must be specified");
  }

  if (!err.IsOk()) {
    std::cerr << "error: unable to create inference context: " << err
              << std::endl;
    exit(1);
  }

  // Obtain a list of the image names to be processed
  std::vector<std::string> image_filenames;

  struct stat name_stat;
  if (stat(argv[optind], &name_stat) != 0) {
    std::cerr << "Failed to find '" << std::string(argv[optind])
              << "': " << strerror(errno) << std::endl;
    exit(1);
  }

  if (name_stat.st_mode & S_IFDIR) {
    const std::string dirname = argv[optind];
    DIR* dir_ptr = opendir(dirname.c_str());
    struct dirent* d_ptr;
    while ((d_ptr = readdir(dir_ptr)) != NULL) {
      const std::string filename = d_ptr->d_name;
      if ((filename != ".") && (filename != "..")) {
        image_filenames.push_back(dirname + "/" + filename);
      }
    }
    closedir(dir_ptr);
  } else {
    image_filenames.push_back(argv[optind]);
  }

  // Sort the filenames so that we always visit them in the same order
  // (readdir does not guarantee any particular order).
  std::sort(image_filenames.begin(), image_filenames.end());

  // Read the raw image as string
  std::vector<std::vector<std::string>> images;
  for (const auto& fn : image_filenames) {
    images.emplace_back();
    auto& image_str = images.back();
    std::ifstream file(fn);
    file >> std::noskipws;
    image_str.emplace_back(
        (std::istreambuf_iterator<char>(file)),
        std::istreambuf_iterator<char>());
    if (image_str.back().empty()) {
      std::cerr << "error: unable to read image file " << fn << std::endl;
      exit(1);
    }
  }

  // this client only send one request for simplicity. So the maximum number
  // of the images to be processed is limited by the maximum batch size
  uint64_t batch_size = ctx->MaxBatchSize();
  if (images.size() > batch_size) {
    std::cerr << "The number of images exceeds maximum batch size, only the"
              << " first " << batch_size << " images, sorted by name"
              << " alphabetically, will be processed" << std::endl;
  }
  batch_size = (images.size() < batch_size) ? images.size() : batch_size;

  // Set the context options to do 1 request. Also request
  // the return type of the result.
  std::unique_ptr<nic::InferContext::Options> options;
  FAIL_IF_ERR(
      nic::InferContext::Options::Create(&options),
      "unable to create inference options");

  options->SetBatchSize(batch_size);
  for (const auto& output : ctx->Outputs()) {
    options->AddClassResult(output, topk);
  }

  FAIL_IF_ERR(ctx->SetRunOptions(*options), "unable to set inference options");

  // Initialize the inputs with the data.
  std::shared_ptr<nic::InferContext::Input> input;
  FAIL_IF_ERR(ctx->GetInput("INPUT", &input), "unable to get INPUT");

  FAIL_IF_ERR(input->Reset(), "unable to reset INPUT");

  for (size_t i = 0; i < batch_size; i++) {
    FAIL_IF_ERR(
        input->SetFromString(images[i]), "unable to set data for INPUT");
  }

  // Send inference request to the inference server.
  std::map<std::string, std::unique_ptr<nic::InferContext::Result>> results;
  FAIL_IF_ERR(ctx->Run(&results), "unable to run model");

  // We expect there to be 1 result. The result may be batched.
  if (results.size() != 1) {
    std::cerr << "error: expected 1 results, got " << results.size()
              << std::endl;
  }

  // Print classification results
  for (size_t i = 0; i < batch_size; i++) {
    // Read the output values if we are performing classification.
    Postprocess(results, image_filenames, batch_size);
  }

  return 0;
}
<|endoftext|>