<commit_before>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity parser.
 */

#include <string>

#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{
ASTPointer<ContractDefinition> parseText(std::string const& _source)
{
	Parser parser;
	return parser.parse(std::make_shared<Scanner>(CharStream(_source)));
}
}

BOOST_AUTO_TEST_SUITE(SolidityParser)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVariable1;\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
{
	char const* text = "contract test {\n"
					   "  uint256 ;\n"
					   "}\n";
	BOOST_CHECK_THROW(parseText(text), ParserError);
}

BOOST_AUTO_TEST_CASE(empty_function)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName(hash160 arg1, address addr) const\n"
					   "    returns (int id)\n"
					   "  { }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(no_function_params)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName() {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(single_function_param)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(function_natspec_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is a test function\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();
	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function");
}

BOOST_AUTO_TEST_CASE(function_normal_comments)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  // We won't see this comment\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();
	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), "");
}

BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is test function 1\n"
					   "  function functionName1(hash hashin) returns (hash hashout) {}\n"
					   "  /// This is test function 2\n"
					   "  function functionName2(hash hashin) returns (hash hashout) {}\n"
					   "  // nothing to see here\n"
					   "  function functionName3(hash hashin) returns (hash hashout) {}\n"
					   "  /// This is test function 4\n"
					   "  function functionName4(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();

	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1");

	BOOST_CHECK_NO_THROW(function = functions.at(1));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2");

	BOOST_CHECK_NO_THROW(function = functions.at(2));
	BOOST_CHECK_EQUAL(function->getDocumentation(), "");

	BOOST_CHECK_NO_THROW(function = functions.at(3));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4");
}

BOOST_AUTO_TEST_CASE(multiline_function_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is a test function\n"
					   "  /// and it has 2 lines\n"
					   "  function functionName1(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();

	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(),
					  " This is a test function\n"
					  " and it has 2 lines");
}

BOOST_AUTO_TEST_CASE(struct_definition)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  struct MyStructName {\n"
					   "    address addr;\n"
					   "    uint256 count;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping)
{
	char const* text = "contract test {\n"
					   "  mapping(address => string) names;\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping_in_struct)
{
	char const* text = "contract test {\n"
					   "  struct test_struct {\n"
					   "    address addr;\n"
					   "    uint256 count;\n"
					   "    mapping(hash => test_struct) self_reference;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
{
	char const* text = "contract test {\n"
					   "  struct test_struct {\n"
					   "    address addr;\n"
					   "    mapping (uint64 => mapping (hash => uint)) complex_mapping;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(variable_definition)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    var b;\n"
					   "    uint256 c;\n"
					   "    mapping(address=>hash) d;\n"
					   "    customtype varname;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    var b = 2;\n"
					   "    uint256 c = 0x87;\n"
					   "    mapping(address=>hash) d;\n"
					   "    string name = \"Solidity\";"
					   "    customtype varname;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(operator_expression)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(complex_expression)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    while (true) { uint256 x = 1; break; continue; } x = 9;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(if_statement)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    if (a >= 8) return 2; else { var b = 7; }\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(else_if_statement)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) returns (address b) {\n"
					   "    if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
{
	char const* text = "contract test {\n"
					   "  function fun() {\n"
					   "    uint64(2);\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<commit_msg>Adding solidity natspec comment inside function body<commit_after>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity parser.
 */

#include <string>

#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{
ASTPointer<ContractDefinition> parseText(std::string const& _source)
{
	Parser parser;
	return parser.parse(std::make_shared<Scanner>(CharStream(_source)));
}
}

BOOST_AUTO_TEST_SUITE(SolidityParser)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVariable1;\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
{
	char const* text = "contract test {\n"
					   "  uint256 ;\n"
					   "}\n";
	BOOST_CHECK_THROW(parseText(text), ParserError);
}

BOOST_AUTO_TEST_CASE(empty_function)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName(hash160 arg1, address addr) const\n"
					   "    returns (int id)\n"
					   "  { }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(no_function_params)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName() {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(single_function_param)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(function_natspec_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is a test function\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();
	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function");
}

BOOST_AUTO_TEST_CASE(function_normal_comments)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  // We won't see this comment\n"
					   "  function functionName(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();
	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), "");
}

BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is test function 1\n"
					   "  function functionName1(hash hashin) returns (hash hashout) {}\n"
					   "  /// This is test function 2\n"
					   "  function functionName2(hash hashin) returns (hash hashout) {}\n"
					   "  // nothing to see here\n"
					   "  function functionName3(hash hashin) returns (hash hashout) {}\n"
					   "  /// This is test function 4\n"
					   "  function functionName4(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();

	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1");

	BOOST_CHECK_NO_THROW(function = functions.at(1));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2");

	BOOST_CHECK_NO_THROW(function = functions.at(2));
	BOOST_CHECK_EQUAL(function->getDocumentation(), "");

	BOOST_CHECK_NO_THROW(function = functions.at(3));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4");
}

BOOST_AUTO_TEST_CASE(multiline_function_documentation)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  /// This is a test function\n"
					   "  /// and it has 2 lines\n"
					   "  function functionName1(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();

	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(),
					  " This is a test function\n"
					  " and it has 2 lines");
}

BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
{
	ASTPointer<ContractDefinition> contract;
	ASTPointer<FunctionDefinition> function;
	char const* text = "contract test {\n"
					   "  /// fun1 description\n"
					   "  function fun1(uint256 a) {\n"
					   "    var b;\n"
					   "    /// I should not interfere with actual natspec comments\n"
					   "    uint256 c;\n"
					   "    mapping(address=>hash) d;\n"
					   "    string name = \"Solidity\";"
					   "  }\n"
					   "  uint256 stateVar;\n"
					   "  /// This is a test function\n"
					   "  /// and it has 2 lines\n"
					   "  function fun(hash hashin) returns (hash hashout) {}\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(contract = parseText(text));
	auto functions = contract->getDefinedFunctions();

	BOOST_CHECK_NO_THROW(function = functions.at(0));
	BOOST_CHECK_EQUAL(function->getDocumentation(), " fun1 description");

	BOOST_CHECK_NO_THROW(function = functions.at(1));
	BOOST_CHECK_EQUAL(function->getDocumentation(),
					  " This is a test function\n"
					  " and it has 2 lines");
}

BOOST_AUTO_TEST_CASE(struct_definition)
{
	char const* text = "contract test {\n"
					   "  uint256 stateVar;\n"
					   "  struct MyStructName {\n"
					   "    address addr;\n"
					   "    uint256 count;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping)
{
	char const* text = "contract test {\n"
					   "  mapping(address => string) names;\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping_in_struct)
{
	char const* text = "contract test {\n"
					   "  struct test_struct {\n"
					   "    address addr;\n"
					   "    uint256 count;\n"
					   "    mapping(hash => test_struct) self_reference;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
{
	char const* text = "contract test {\n"
					   "  struct test_struct {\n"
					   "    address addr;\n"
					   "    mapping (uint64 => mapping (hash => uint)) complex_mapping;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(variable_definition)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    var b;\n"
					   "    uint256 c;\n"
					   "    mapping(address=>hash) d;\n"
					   "    customtype varname;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    var b = 2;\n"
					   "    uint256 c = 0x87;\n"
					   "    mapping(address=>hash) d;\n"
					   "    string name = \"Solidity\";"
					   "    customtype varname;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(operator_expression)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(complex_expression)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    while (true) { uint256 x = 1; break; continue; } x = 9;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(if_statement)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) {\n"
					   "    if (a >= 8) return 2; else { var b = 7; }\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(else_if_statement)
{
	char const* text = "contract test {\n"
					   "  function fun(uint256 a) returns (address b) {\n"
					   "    if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
{
	char const* text = "contract test {\n"
					   "  function fun() {\n"
					   "    uint64(2);\n"
					   "  }\n"
					   "}\n";
	BOOST_CHECK_NO_THROW(parseText(text));
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Original authors — credit is appreciated but not required:

        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 —
            Vladimír Vondruš <mosra@centrum.cz>
        2018 — Jonathan Hale <squareys@googlemail.com>

    This is free and unencumbered software released into the public domain.

    Anyone is free to copy, modify, publish, use, compile, sell, or distribute
    this software, either in source code form or as a compiled binary, for any
    purpose, commercial or non-commercial, and by any means.

    In jurisdictions that recognize copyright laws, the author or authors of
    this software dedicate any and all copyright interest in the software to
    the public domain. We make this dedication for the benefit of the public
    at large and to the detriment of our heirs and successors. We intend this
    dedication to be an overt act of relinquishment in perpetuity of all
    present and future rights to this software under copyright law.

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

#include <Magnum/Magnum.h>
#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/Context.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cylinder.h>
#include <Magnum/Primitives/UVSphere.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>

#include <Leap.h>

namespace Magnum { namespace Examples {

class LeapMotionExample: public Platform::Application {
    public:
        explicit LeapMotionExample(const Arguments& arguments);

    private:
        void drawEvent() override;
        void drawBone(const Leap::Bone& bone, bool start, bool end, const Color3& color);

        GL::Buffer _buffers[4];
        GL::Mesh _cylinder{NoCreate};
        GL::Mesh _sphere{NoCreate};

        Shaders::Phong _shader;

        const Matrix4 _projectionMatrix = Matrix4::perspectiveProjection(90.0_degf, 3.0f/2.0f, 0.01f, 25.0f);
        const Matrix4 _viewMatrix = Matrix4::translation({0.0f, -3.0f, -5.0f});

        /* LeapMotion specific members */
        Leap::Controller _controller;
};

LeapMotionExample::LeapMotionExample(const Arguments& arguments):
    Platform::Application(arguments, Configuration{}.setTitle("Magnum Leap Motion Example").setSampleCount(16))
{
    /* To use LeapMotion with VR, you should set
       _controller.setPolicy(Leap::Controller::PolicyFlag::POLICY_OPTIMIZE_HMD); */

    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);

    /* As we sample the Leap controller every frame, enabling vsyc will cause more latency,
       but seems to produce more stable results.
       To reduce latency and fully utlize the ~115 fps hand tracking, disable vsync. */
    setSwapInterval(1);

    Containers::Array<char> indexData;
    MeshIndexType indexType;
    UnsignedInt indexStart, indexEnd;
    {
        /* Setup cylinder mesh */
        const Trade::MeshData3D cylinder = Primitives::cylinderSolid(2, 16, 0.5f);
        _buffers[0].setData(MeshTools::interleave(cylinder.positions(0), cylinder.normals(0)), GL::BufferUsage::StaticDraw);

        std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(cylinder.indices());
        _buffers[1].setData(indexData, GL::BufferUsage::StaticDraw);

        _cylinder = GL::Mesh{cylinder.primitive()};
        _cylinder.setCount(cylinder.indices().size())
                 .addVertexBuffer(_buffers[0], 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{})
                 .setIndexBuffer(_buffers[1], 0, indexType, indexStart, indexEnd);
    }
    {
        /* Setup sphere mesh */
        const Trade::MeshData3D sphere = Primitives::uvSphereSolid(16, 16);
        _buffers[2].setData(MeshTools::interleave(sphere.positions(0), sphere.normals(0)), GL::BufferUsage::StaticDraw);

        std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(sphere.indices());
        _buffers[3].setData(indexData, GL::BufferUsage::StaticDraw);

        _sphere = GL::Mesh{sphere.primitive()};
        _sphere.setCount(sphere.indices().size())
               .addVertexBuffer(_buffers[2], 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{})
               .setIndexBuffer(_buffers[3], 0, indexType, indexStart, indexEnd);
    }

    /* Setup shader */
    _shader.setSpecularColor(Color3(1.0f))
           .setShininess(20)
           .setLightPosition({0.0f, 5.0f, 5.0f});
}

void LeapMotionExample::drawEvent() {
    /* Poll leap controller */
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);

    /* Render scene */
    if(_controller.isConnected()) {
        const Matrix4 viewProjMatrix = _projectionMatrix*_viewMatrix;
        _shader.setProjectionMatrix(viewProjMatrix);

        Leap::Frame frame = _controller.frame();
        for(const Leap::Hand& hand : frame.hands()) {
            const Color3 handColor = hand.isRight() ? Color3{1.0f, 0.0f, 0.0f} : Color3{0.0f, 1.0f, 1.0f};

            for(const Leap::Finger& finger : hand.fingers()) {
                for(int b = 0; b < 4; ++b) {
                    /* Leave out first bones of ring and middle finger, looks better */
                    if(b == 0 && (finger.type() == Leap::Finger::Type::TYPE_MIDDLE || finger.type() == Leap::Finger::Type::TYPE_RING)) continue;

                    const auto& bone = finger.bone(Leap::Bone::Type(b));
                    /* Only draw end on last bones */
                    drawBone(bone, true, b == 3, handColor);
                }
            }
        }
    }

    swapBuffers();
    redraw();
}

void LeapMotionExample::drawBone(const Leap::Bone& bone, bool start, bool end, const Color3& color) {
    const Vector3 boneCenter = 0.01f*Vector3::from(bone.center().toFloatPointer());
    const Vector3 boneDirection = 0.01f*Vector3::from(bone.direction().toFloatPointer());
    const Float boneLength = 0.01f*bone.length();

    const Matrix4 rotX = Matrix4::rotationX(90.0_degf);
    /* Draw cylinder */
    {
        const Matrix4 transformation = Matrix4::translation(boneCenter)*Matrix4::from(bone.basis().toArray4x4())*rotX*Matrix4::scaling({0.06f, boneLength, 0.06f});
        _shader.setDiffuseColor(Color3{1.0f, 1.0f, 1.0f})
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _cylinder.draw(_shader);
    }

    /* Draw sphere at start of the bone */
    if(start) {
        const Vector3 prevJoint = 0.01f*Vector3::from(bone.prevJoint().toFloatPointer());
        const Matrix4 transformation = Matrix4::translation(prevJoint)*rotX*Matrix4::scaling(Vector3{0.08f});
        _shader.setDiffuseColor(color)
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _sphere.draw(_shader);
    }

    /* Draw sphere at end of the bone */
    if(end) {
        const Vector3 nextJoint = 0.01f*Vector3::from(bone.nextJoint().toFloatPointer());
        const Matrix4 transformation = Matrix4::translation(nextJoint)*rotX*Matrix4::scaling(Vector3{0.08f});
        _shader.setDiffuseColor(color)
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _sphere.draw(_shader);
    }
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::LeapMotionExample)
<commit_msg>leapmotion: adapt to Magnum API changes<commit_after>/*
    This file is part of Magnum.

    Original authors — credit is appreciated but not required:

        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 —
            Vladimír Vondruš <mosra@centrum.cz>
        2018 — Jonathan Hale <squareys@googlemail.com>

    This is free and unencumbered software released into the public domain.

    Anyone is free to copy, modify, publish, use, compile, sell, or distribute
    this software, either in source code form or as a compiled binary, for any
    purpose, commercial or non-commercial, and by any means.

    In jurisdictions that recognize copyright laws, the author or authors of
    this software dedicate any and all copyright interest in the software to
    the public domain. We make this dedication for the benefit of the public
    at large and to the detriment of our heirs and successors. We intend this
    dedication to be an overt act of relinquishment in perpetuity of all
    present and future rights to this software under copyright law.

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

#include <Magnum/Magnum.h>
#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/Context.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Framebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/GL/Renderer.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cylinder.h>
#include <Magnum/Primitives/UVSphere.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>

#include <Leap.h>

namespace Magnum { namespace Examples {

using namespace Math::Literals;

class LeapMotionExample: public Platform::Application {
    public:
        explicit LeapMotionExample(const Arguments& arguments);

    private:
        void drawEvent() override;
        void drawBone(const Leap::Bone& bone, bool start, bool end, const Color3& color);

        GL::Buffer _buffers[4];
        GL::Mesh _cylinder{NoCreate};
        GL::Mesh _sphere{NoCreate};

        Shaders::Phong _shader;

        const Matrix4 _projectionMatrix = Matrix4::perspectiveProjection(90.0_degf, 3.0f/2.0f, 0.01f, 25.0f);
        const Matrix4 _viewMatrix = Matrix4::translation({0.0f, -3.0f, -5.0f});

        /* LeapMotion specific members */
        Leap::Controller _controller;
};

LeapMotionExample::LeapMotionExample(const Arguments& arguments):
    Platform::Application(arguments, Configuration{}.setTitle("Magnum Leap Motion Example"), GLConfiguration{}.setSampleCount(16))
{
    /* To use LeapMotion with VR, you should set
       _controller.setPolicy(Leap::Controller::PolicyFlag::POLICY_OPTIMIZE_HMD); */

    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);

    /* As we sample the Leap controller every frame, enabling vsyc will cause more latency,
       but seems to produce more stable results.
       To reduce latency and fully utlize the ~115 fps hand tracking, disable vsync. */
    setSwapInterval(1);

    Containers::Array<char> indexData;
    MeshIndexType indexType;
    UnsignedInt indexStart, indexEnd;
    {
        /* Setup cylinder mesh */
        const Trade::MeshData3D cylinder = Primitives::cylinderSolid(2, 16, 0.5f);
        _buffers[0].setData(MeshTools::interleave(cylinder.positions(0), cylinder.normals(0)), GL::BufferUsage::StaticDraw);

        std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(cylinder.indices());
        _buffers[1].setData(indexData, GL::BufferUsage::StaticDraw);

        _cylinder = GL::Mesh{cylinder.primitive()};
        _cylinder.setCount(cylinder.indices().size())
                 .addVertexBuffer(_buffers[0], 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{})
                 .setIndexBuffer(_buffers[1], 0, indexType, indexStart, indexEnd);
    }
    {
        /* Setup sphere mesh */
        const Trade::MeshData3D sphere = Primitives::uvSphereSolid(16, 16);
        _buffers[2].setData(MeshTools::interleave(sphere.positions(0), sphere.normals(0)), GL::BufferUsage::StaticDraw);

        std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(sphere.indices());
        _buffers[3].setData(indexData, GL::BufferUsage::StaticDraw);

        _sphere = GL::Mesh{sphere.primitive()};
        _sphere.setCount(sphere.indices().size())
               .addVertexBuffer(_buffers[2], 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{})
               .setIndexBuffer(_buffers[3], 0, indexType, indexStart, indexEnd);
    }

    /* Setup shader */
    _shader.setSpecularColor(Color3(1.0f))
           .setShininess(20)
           .setLightPosition({0.0f, 5.0f, 5.0f});
}

void LeapMotionExample::drawEvent() {
    /* Poll leap controller */
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);

    /* Render scene */
    if(_controller.isConnected()) {
        const Matrix4 viewProjMatrix = _projectionMatrix*_viewMatrix;
        _shader.setProjectionMatrix(viewProjMatrix);

        Leap::Frame frame = _controller.frame();
        for(const Leap::Hand& hand : frame.hands()) {
            const Color3 handColor = hand.isRight() ? Color3{1.0f, 0.0f, 0.0f} : Color3{0.0f, 1.0f, 1.0f};

            for(const Leap::Finger& finger : hand.fingers()) {
                for(int b = 0; b < 4; ++b) {
                    /* Leave out first bones of ring and middle finger, looks better */
                    if(b == 0 && (finger.type() == Leap::Finger::Type::TYPE_MIDDLE || finger.type() == Leap::Finger::Type::TYPE_RING)) continue;

                    const auto& bone = finger.bone(Leap::Bone::Type(b));
                    /* Only draw end on last bones */
                    drawBone(bone, true, b == 3, handColor);
                }
            }
        }
    }

    swapBuffers();
    redraw();
}

void LeapMotionExample::drawBone(const Leap::Bone& bone, bool start, bool end, const Color3& color) {
    const Vector3 boneCenter = 0.01f*Vector3::from(bone.center().toFloatPointer());
    const Vector3 boneDirection = 0.01f*Vector3::from(bone.direction().toFloatPointer());
    const Float boneLength = 0.01f*bone.length();

    const Matrix4 rotX = Matrix4::rotationX(90.0_degf);
    /* Draw cylinder */
    {
        const Matrix4 transformation = Matrix4::translation(boneCenter)*Matrix4::from(bone.basis().toArray4x4())*rotX*Matrix4::scaling({0.06f, boneLength, 0.06f});
        _shader.setDiffuseColor(Color3{1.0f, 1.0f, 1.0f})
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _cylinder.draw(_shader);
    }

    /* Draw sphere at start of the bone */
    if(start) {
        const Vector3 prevJoint = 0.01f*Vector3::from(bone.prevJoint().toFloatPointer());
        const Matrix4 transformation = Matrix4::translation(prevJoint)*rotX*Matrix4::scaling(Vector3{0.08f});
        _shader.setDiffuseColor(color)
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _sphere.draw(_shader);
    }

    /* Draw sphere at end of the bone */
    if(end) {
        const Vector3 nextJoint = 0.01f*Vector3::from(bone.nextJoint().toFloatPointer());
        const Matrix4 transformation = Matrix4::translation(nextJoint)*rotX*Matrix4::scaling(Vector3{0.08f});
        _shader.setDiffuseColor(color)
               .setTransformationMatrix(transformation)
               .setNormalMatrix(transformation.rotationScaling());
        _sphere.draw(_shader);
    }
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::LeapMotionExample)
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(simple-rtmp-server)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

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

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

#ifndef SRS_APP_PITHY_PRINT_HPP
#define SRS_APP_PITHY_PRINT_HPP

/*
#include <srs_app_pithy_print.hpp>
*/

#include <srs_core.hpp>

#include <srs_app_reload.hpp>

/**
* the stage info to calc the age.
*/
class SrsStageInfo : public ISrsReloadHandler
{
public:
    int stage_id;
    int pithy_print_time_ms;
    int nb_clients;
public:
    int64_t age;
public:
    SrsStageInfo(int _stage_id);
    virtual ~SrsStageInfo();
    virtual void update_print_time();
public:
    virtual void elapse(int64_t diff);
    virtual bool can_print();
public:
    virtual int on_reload_pithy_print();
};

/**
* the stage is used for a collection of object to do print,
* the print time in a stage is constant and not changed.
* for example, stage #1 for all play clients, print time is 3s,
* if there is 10clients, then all clients should print in 10*3s.
* Usage:
        SrsPithyPrint* pprint = SrsPithyPrint::create_rtmp_play();
        SrsAutoFree(SrsPithyPrint, pprint);
        while (true) {
            pprint->elapse();
            if (pprint->can_print()) {
                // print pithy message.
                // user can get the elapse time by: pprint->age()
            }
            // read and write RTMP messages.
        }
*/
class SrsPithyPrint
{
private:
    int client_id;
    int stage_id;
    // in ms.
    int64_t _age;
    int64_t previous_tick;
private:
    SrsPithyPrint(int _stage_id);
public:
    static SrsPithyPrint* create_rtmp_play();
    static SrsPithyPrint* create_rtmp_publish();
    static SrsPithyPrint* create_hls();
    static SrsPithyPrint* create_forwarder();
    static SrsPithyPrint* create_encoder();
    static SrsPithyPrint* create_ingester();
    static SrsPithyPrint* create_edge();
    static SrsPithyPrint* create_caster();
    static SrsPithyPrint* create_http_stream();
    static SrsPithyPrint* create_http_stream_cache();
    virtual ~SrsPithyPrint();
private:
    /**
    * enter the specified stage, return the client id.
    */
    virtual int enter_stage();
    /**
    * leave the specified stage, release the client id.
    */
    virtual void leave_stage();
public:
    /**
    * auto calc the elapse time
    */
    virtual void elapse();
    /**
    * whether current client can print.
    */
    virtual bool can_print();
    /**
    * get the elapsed time in ms.
    */
    virtual int64_t age();
};

#endif
<commit_msg>refine the pithy print mechenism.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(simple-rtmp-server)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

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

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

#ifndef SRS_APP_PITHY_PRINT_HPP
#define SRS_APP_PITHY_PRINT_HPP

/*
#include <srs_app_pithy_print.hpp>
*/

#include <srs_core.hpp>

#include <srs_app_reload.hpp>

/**
* the stage info to calc the age.
*/
class SrsStageInfo : public ISrsReloadHandler
{
public:
    int stage_id;
    int pithy_print_time_ms;
    int nb_clients;
public:
    int64_t age;
public:
    SrsStageInfo(int _stage_id);
    virtual ~SrsStageInfo();
    virtual void update_print_time();
public:
    virtual void elapse(int64_t diff);
    virtual bool can_print();
public:
    virtual int on_reload_pithy_print();
};

/**
 * the stage is used for a collection of object to do print,
 * the print time in a stage is constant and not changed,
 * that is, we always got one message to print every specified time.
 *
 * for example, stage #1 for all play clients, print time is 3s,
 * if there is 1client, it will print every 3s.
 * if there is 10clients, random select one to print every 3s.
 * Usage:
         SrsPithyPrint* pprint = SrsPithyPrint::create_rtmp_play();
         SrsAutoFree(SrsPithyPrint, pprint);
         while (true) {
             pprint->elapse();
             if (pprint->can_print()) {
                 // print pithy message.
                 // user can get the elapse time by: pprint->age()
             }
             // read and write RTMP messages.
         }
 */
class SrsPithyPrint
{
private:
    int client_id;
    int stage_id;
    // in ms.
    int64_t _age;
    int64_t previous_tick;
private:
    SrsPithyPrint(int _stage_id);
public:
    static SrsPithyPrint* create_rtmp_play();
    static SrsPithyPrint* create_rtmp_publish();
    static SrsPithyPrint* create_hls();
    static SrsPithyPrint* create_forwarder();
    static SrsPithyPrint* create_encoder();
    static SrsPithyPrint* create_ingester();
    static SrsPithyPrint* create_edge();
    static SrsPithyPrint* create_caster();
    static SrsPithyPrint* create_http_stream();
    static SrsPithyPrint* create_http_stream_cache();
    virtual ~SrsPithyPrint();
private:
    /**
    * enter the specified stage, return the client id.
    */
    virtual int enter_stage();
    /**
    * leave the specified stage, release the client id.
    */
    virtual void leave_stage();
public:
    /**
    * auto calc the elapse time
    */
    virtual void elapse();
    /**
    * whether current client can print.
    */
    virtual bool can_print();
    /**
    * get the elapsed time in ms.
    */
    virtual int64_t age();
};

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/tasks/deciders/path_decider/path_decider.h"

#include <string>

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_context.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/proto/decision.pb.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::VehicleConfigHelper;

PathDecider::PathDecider(const TaskConfig &config) : Task(config) {
  SetName("PathDecider");
}

Status PathDecider::Execute(Frame *frame,
                            ReferenceLineInfo *reference_line_info) {
  Task::Execute(frame, reference_line_info);
  return Process(reference_line_info, reference_line_info->path_data(),
                 reference_line_info->path_decision());
}

Status PathDecider::Process(const ReferenceLineInfo *reference_line_info,
                            const PathData &path_data,
                            PathDecision *const path_decision) {
  CHECK_NOTNULL(path_decision);
  std::string blocking_obstacle_id =
      reference_line_info->GetBlockingObstacleId();
  if (!MakeObjectDecision(path_data, blocking_obstacle_id, path_decision)) {
    AERROR << "Failed to make decision based on tunnel";
    return Status(ErrorCode::PLANNING_ERROR, "dp_road_graph decision ");
  }
  return Status::OK();
}

bool PathDecider::MakeObjectDecision(const PathData &path_data,
                                     const std::string &blocking_obstacle_id,
                                     PathDecision *const path_decision) {
  DCHECK_NOTNULL(path_decision);
  if (!MakeStaticObstacleDecision(path_data, blocking_obstacle_id,
                                  path_decision)) {
    AERROR << "Failed to make decisions for static obstacles";
    return false;
  }
  return true;
}

// TODO(jiacheng): eventually this entire "path_decider" should be retired.
// Before it gets retired, its logics are slightly modified so that everything
// still works well for now.
bool PathDecider::MakeStaticObstacleDecision(
    const PathData &path_data, const std::string &blocking_obstacle_id,
    PathDecision *const path_decision) {
  // Sanity checks and get important values.
  DCHECK_NOTNULL(path_decision);
  const auto &frenet_path = path_data.frenet_frame_path();
  if (frenet_path.empty()) {
    AERROR << "Path is empty.";
    return false;
  }
  const double half_width =
      common::VehicleConfigHelper::GetConfig().vehicle_param().width() / 2.0;
  const double lateral_radius = half_width + FLAGS_lateral_ignore_buffer;

  // Go through every obstalce and make decisions.
  for (const auto *obstacle : path_decision->obstacles().Items()) {
    // - skip decision making for moving vehicles or unknowns.
    bool is_bycycle_or_pedestrain =
        (obstacle->Perception().type() ==
             perception::PerceptionObstacle::BICYCLE ||
         obstacle->Perception().type() ==
             perception::PerceptionObstacle::PEDESTRIAN);
    if (!is_bycycle_or_pedestrain && !obstacle->IsStatic()) {
      continue;
    }
    // - skip decision making for obstacles with IGNORE/STOP decisions already.
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_ignore() &&
        obstacle->HasLateralDecision() &&
        obstacle->LateralDecision().has_ignore()) {
      continue;
    }
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_stop()) {
      // STOP decision
      continue;
    }
    // - add STOP decision for blocking obstacles.
    if (obstacle->Id() == blocking_obstacle_id &&
        !PlanningContext::Instance()
             ->planning_status()
             .path_decider()
             .is_in_path_lane_borrow_scenario()) {
      // Add stop decision
      ADEBUG << "Blocking obstacle = " << blocking_obstacle_id;
      ObjectDecisionType object_decision;
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);
      path_decision->AddLongitudinalDecision("PathDecider/blocking_obstacle",
                                             obstacle->Id(), object_decision);
      continue;
    }
    // - skip decision making for clear-zone obstacles.
    if (obstacle->reference_line_st_boundary().boundary_type() ==
        STBoundary::BoundaryType::KEEP_CLEAR) {
      continue;
    }

    // 0. IGNORE by default and if obstacle is not in path s at all.
    ObjectDecisionType object_decision;
    object_decision.mutable_ignore();
    const auto &sl_boundary = obstacle->PerceptionSLBoundary();
    if (sl_boundary.end_s() < frenet_path.front().s() ||
        sl_boundary.start_s() > frenet_path.back().s()) {
      path_decision->AddLongitudinalDecision("PathDecider/not-in-s",
                                             obstacle->Id(), object_decision);
      path_decision->AddLateralDecision("PathDecider/not-in-s", obstacle->Id(),
                                        object_decision);
      continue;
    }

    const auto frenet_point = frenet_path.GetNearestPoint(sl_boundary);
    const double curr_l = frenet_point.l();
    double min_nudge_l =
        half_width + FLAGS_static_decision_nudge_l_buffer / 2.0;

    if (curr_l - lateral_radius > sl_boundary.end_l() ||
        curr_l + lateral_radius < sl_boundary.start_l()) {
      // 1. IGNORE if laterally too far away.
      path_decision->AddLateralDecision("PathDecider/not-in-l", obstacle->Id(),
                                        object_decision);
    } else if (sl_boundary.end_l() >= curr_l - min_nudge_l &&
               sl_boundary.start_l() <= curr_l + min_nudge_l) {
      // 2. STOP if laterally too overlapping.
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);

      if (path_decision->MergeWithMainStop(
              object_decision.stop(), obstacle->Id(),
              reference_line_info_->reference_line(),
              reference_line_info_->AdcSlBoundary())) {
        path_decision->AddLongitudinalDecision("PathDecider/nearest-stop",
                                               obstacle->Id(), object_decision);
      } else {
        ObjectDecisionType object_decision;
        object_decision.mutable_ignore();
        path_decision->AddLongitudinalDecision("PathDecider/not-nearest-stop",
                                               obstacle->Id(), object_decision);
      }
    } else if (FLAGS_enable_nudge_decision) {
      // 3. NUDGE if laterally very close.
      if (sl_boundary.end_l() < curr_l - min_nudge_l) {  // &&
        // sl_boundary.end_l() > curr_l - min_nudge_l - 0.3) {
        // LEFT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::LEFT_NUDGE);
        object_nudge_ptr->set_distance_l(FLAGS_nudge_distance_obstacle);
        path_decision->AddLateralDecision("PathDecider/left-nudge",
                                          obstacle->Id(), object_decision);
      } else if (sl_boundary.start_l() > curr_l + min_nudge_l) {  // &&
        // sl_boundary.start_l() < curr_l + min_nudge_l + 0.3) {
        // RIGHT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::RIGHT_NUDGE);
        object_nudge_ptr->set_distance_l(-FLAGS_nudge_distance_obstacle);
        path_decision->AddLateralDecision("PathDecider/right-nudge",
                                          obstacle->Id(), object_decision);
      }
    }
  }

  return true;
}

ObjectStop PathDecider::GenerateObjectStopDecision(
    const Obstacle &obstacle) const {
  ObjectStop object_stop;

  double stop_distance = obstacle.MinRadiusStopDistance(
      VehicleConfigHelper::GetConfig().vehicle_param());
  object_stop.set_reason_code(StopReasonCode::STOP_REASON_OBSTACLE);
  object_stop.set_distance_s(-stop_distance);

  const double stop_ref_s =
      obstacle.PerceptionSLBoundary().start_s() - stop_distance;
  const auto stop_ref_point =
      reference_line_info_->reference_line().GetReferencePoint(stop_ref_s);
  object_stop.mutable_stop_point()->set_x(stop_ref_point.x());
  object_stop.mutable_stop_point()->set_y(stop_ref_point.y());
  object_stop.set_stop_heading(stop_ref_point.heading());
  return object_stop;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: nudge decision for all static and not virtual obstacle, not only bicycle or pedestrian<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/tasks/deciders/path_decider/path_decider.h"

#include <string>

#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/util/util.h"
#include "modules/planning/common/planning_context.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/proto/decision.pb.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::VehicleConfigHelper;

PathDecider::PathDecider(const TaskConfig &config) : Task(config) {
  SetName("PathDecider");
}

Status PathDecider::Execute(Frame *frame,
                            ReferenceLineInfo *reference_line_info) {
  Task::Execute(frame, reference_line_info);
  return Process(reference_line_info, reference_line_info->path_data(),
                 reference_line_info->path_decision());
}

Status PathDecider::Process(const ReferenceLineInfo *reference_line_info,
                            const PathData &path_data,
                            PathDecision *const path_decision) {
  CHECK_NOTNULL(path_decision);
  std::string blocking_obstacle_id =
      reference_line_info->GetBlockingObstacleId();
  if (!MakeObjectDecision(path_data, blocking_obstacle_id, path_decision)) {
    AERROR << "Failed to make decision based on tunnel";
    return Status(ErrorCode::PLANNING_ERROR, "dp_road_graph decision ");
  }
  return Status::OK();
}

bool PathDecider::MakeObjectDecision(const PathData &path_data,
                                     const std::string &blocking_obstacle_id,
                                     PathDecision *const path_decision) {
  DCHECK_NOTNULL(path_decision);
  if (!MakeStaticObstacleDecision(path_data, blocking_obstacle_id,
                                  path_decision)) {
    AERROR << "Failed to make decisions for static obstacles";
    return false;
  }
  return true;
}

// TODO(jiacheng): eventually this entire "path_decider" should be retired.
// Before it gets retired, its logics are slightly modified so that everything
// still works well for now.
bool PathDecider::MakeStaticObstacleDecision(
    const PathData &path_data, const std::string &blocking_obstacle_id,
    PathDecision *const path_decision) {
  // Sanity checks and get important values.
  DCHECK_NOTNULL(path_decision);
  const auto &frenet_path = path_data.frenet_frame_path();
  if (frenet_path.empty()) {
    AERROR << "Path is empty.";
    return false;
  }
  const double half_width =
      common::VehicleConfigHelper::GetConfig().vehicle_param().width() / 2.0;
  const double lateral_radius = half_width + FLAGS_lateral_ignore_buffer;

  // Go through every obstalce and make decisions.
  for (const auto *obstacle : path_decision->obstacles().Items()) {
    const std::string& obstacle_id = obstacle->Id();
    const std::string obstacle_type_name =
        PerceptionObstacle_Type_Name(obstacle->Perception().type());
    ADEBUG << "obstacle_id[<< " << obstacle_id
           << "] type[" << obstacle_type_name << "]";

    if (!obstacle->IsStatic() || obstacle->IsVirtual()) {
      continue;
    }
    // - skip decision making for obstacles with IGNORE/STOP decisions already.
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_ignore() &&
        obstacle->HasLateralDecision() &&
        obstacle->LateralDecision().has_ignore()) {
      continue;
    }
    if (obstacle->HasLongitudinalDecision() &&
        obstacle->LongitudinalDecision().has_stop()) {
      // STOP decision
      continue;
    }
    // - add STOP decision for blocking obstacles.
    if (obstacle->Id() == blocking_obstacle_id &&
        !PlanningContext::Instance()
             ->planning_status()
             .path_decider()
             .is_in_path_lane_borrow_scenario()) {
      // Add stop decision
      ADEBUG << "Blocking obstacle = " << blocking_obstacle_id;
      ObjectDecisionType object_decision;
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);
      path_decision->AddLongitudinalDecision("PathDecider/blocking_obstacle",
                                             obstacle->Id(), object_decision);
      continue;
    }
    // - skip decision making for clear-zone obstacles.
    if (obstacle->reference_line_st_boundary().boundary_type() ==
        STBoundary::BoundaryType::KEEP_CLEAR) {
      continue;
    }

    // 0. IGNORE by default and if obstacle is not in path s at all.
    ObjectDecisionType object_decision;
    object_decision.mutable_ignore();
    const auto &sl_boundary = obstacle->PerceptionSLBoundary();
    if (sl_boundary.end_s() < frenet_path.front().s() ||
        sl_boundary.start_s() > frenet_path.back().s()) {
      path_decision->AddLongitudinalDecision("PathDecider/not-in-s",
                                             obstacle->Id(), object_decision);
      path_decision->AddLateralDecision("PathDecider/not-in-s", obstacle->Id(),
                                        object_decision);
      continue;
    }

    const auto frenet_point = frenet_path.GetNearestPoint(sl_boundary);
    const double curr_l = frenet_point.l();
    double min_nudge_l =
        half_width + FLAGS_static_decision_nudge_l_buffer / 2.0;

    if (curr_l - lateral_radius > sl_boundary.end_l() ||
        curr_l + lateral_radius < sl_boundary.start_l()) {
      // 1. IGNORE if laterally too far away.
      path_decision->AddLateralDecision("PathDecider/not-in-l", obstacle->Id(),
                                        object_decision);
    } else if (sl_boundary.end_l() >= curr_l - min_nudge_l &&
               sl_boundary.start_l() <= curr_l + min_nudge_l) {
      // 2. STOP if laterally too overlapping.
      *object_decision.mutable_stop() = GenerateObjectStopDecision(*obstacle);

      if (path_decision->MergeWithMainStop(
              object_decision.stop(), obstacle->Id(),
              reference_line_info_->reference_line(),
              reference_line_info_->AdcSlBoundary())) {
        path_decision->AddLongitudinalDecision("PathDecider/nearest-stop",
                                               obstacle->Id(), object_decision);
      } else {
        ObjectDecisionType object_decision;
        object_decision.mutable_ignore();
        path_decision->AddLongitudinalDecision("PathDecider/not-nearest-stop",
                                               obstacle->Id(), object_decision);
      }
    } else if (FLAGS_enable_nudge_decision) {
      // 3. NUDGE if laterally very close.
      if (sl_boundary.end_l() < curr_l - min_nudge_l) {  // &&
        // sl_boundary.end_l() > curr_l - min_nudge_l - 0.3) {
        // LEFT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::LEFT_NUDGE);
        object_nudge_ptr->set_distance_l(FLAGS_nudge_distance_obstacle);
        path_decision->AddLateralDecision("PathDecider/left-nudge",
                                          obstacle->Id(), object_decision);
      } else if (sl_boundary.start_l() > curr_l + min_nudge_l) {  // &&
        // sl_boundary.start_l() < curr_l + min_nudge_l + 0.3) {
        // RIGHT_NUDGE
        ObjectNudge *object_nudge_ptr = object_decision.mutable_nudge();
        object_nudge_ptr->set_type(ObjectNudge::RIGHT_NUDGE);
        object_nudge_ptr->set_distance_l(-FLAGS_nudge_distance_obstacle);
        path_decision->AddLateralDecision("PathDecider/right-nudge",
                                          obstacle->Id(), object_decision);
      }
    }
  }

  return true;
}

ObjectStop PathDecider::GenerateObjectStopDecision(
    const Obstacle &obstacle) const {
  ObjectStop object_stop;

  double stop_distance = obstacle.MinRadiusStopDistance(
      VehicleConfigHelper::GetConfig().vehicle_param());
  object_stop.set_reason_code(StopReasonCode::STOP_REASON_OBSTACLE);
  object_stop.set_distance_s(-stop_distance);

  const double stop_ref_s =
      obstacle.PerceptionSLBoundary().start_s() - stop_distance;
  const auto stop_ref_point =
      reference_line_info_->reference_line().GetReferencePoint(stop_ref_s);
  object_stop.mutable_stop_point()->set_x(stop_ref_point.x());
  object_stop.mutable_stop_point()->set_y(stop_ref_point.y());
  object_stop.set_stop_heading(stop_ref_point.heading());
  return object_stop;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalExecutor.h"
#include "IncrementalJIT.h"
#include "Threading.h"

#include "cling/Interpreter/Value.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/Basic/Diagnostic.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"

#ifdef LLVM_ON_WIN32
extern "C"
char *__unDName(char *demangled, const char *mangled, int out_len,
                void * (* pAlloc )(size_t), void (* pFree )(void *),
                unsigned short int flags);
#else
#include <cxxabi.h>
#endif

using namespace llvm;

namespace cling {

IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags):
  m_CurrentAtExitModule(0)
#if 0
  : m_Diags(diags)
#endif
{

  // MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
  std::atomic_flag_clear( &m_AtExitFuncsSpinLock );

  // No need to protect this access of m_AtExitFuncs, since nobody
  // can use this object yet.
  m_AtExitFuncs.reserve(256);

  m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
}

// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
IncrementalExecutor::~IncrementalExecutor() {}

std::unique_ptr<TargetMachine>
  IncrementalExecutor::CreateHostTargetMachine() const {
  // TODO: make this configurable.
  Triple TheTriple(sys::getProcessTriple());
#ifdef _WIN32
  /*
	* MCJIT works on Windows, but currently only through ELF object format.
	*/
  TheTriple.setObjectFormat(llvm::Triple::ELF);
#endif
  std::string Error;
  const Target *TheTarget
    = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
  if (!TheTarget) {
    llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
                 << Error;
  }

  std::string MCPU;
  std::string FeaturesStr;

  TargetOptions Options = TargetOptions();
  Options.NoFramePointerElim = 1;
  Options.JITEmitDebugInfo = 1;
  Reloc::Model RelocModel = Reloc::Default;
  CodeModel::Model CMModel = CodeModel::JITDefault;
  CodeGenOpt::Level OptLevel = CodeGenOpt::Less;

  std::unique_ptr<TargetMachine> TM;
  TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
                                          MCPU, FeaturesStr,
                                          Options,
                                          RelocModel, CMModel,
                                          OptLevel));
  return std::move(TM);
}

void IncrementalExecutor::shuttingDown() {
  // No need to protect this access, since hopefully there is no concurrent
  // shutdown request.
  for (size_t I = 0, N = m_AtExitFuncs.size(); I < N; ++I) {
    const CXAAtExitElement& AEE = m_AtExitFuncs[N - I - 1];
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) {
  // Register a CXAAtExit function
  cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
  m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule));
}

void unresolvedSymbol()
{
  // This might get called recursively, or a billion of times. Do not generate
  // useless output; unresolvedSymbol() is always handed out with an error
  // message - that's enough.
  //llvm::errs() << "IncrementalExecutor: calling unresolved symbol, "
  //  "see previous error message!\n";

  // throw exception instead?
}

void* IncrementalExecutor::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    //llvm::errs() << "IncrementalExecutor: use of undefined symbol '"
    //             << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
IncrementalExecutor::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  return HandleMissingFunction(mangled_name);
}

#if 0
// FIXME: employ to empty module dependencies *within* the *current* module.
static void
freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
                               funcsToFree, llvm::ExecutionEngine* engine) {
  llvm::SmallPtrSet<llvm::Function*, 40> funcsToFreeUnique;
  for (size_t i = 0; i < funcsToFree.size(); ++i) {
    llvm::Function* func = funcsToFree[i];
    assert(func && "Cannot free NULL function");
    if (funcsToFreeUnique.insert(func).second) {
      for (llvm::Value::use_iterator IU = func->use_begin(),
             EU = func->use_end(); IU != EU; ++IU) {
        llvm::Instruction* instUser = llvm::dyn_cast<llvm::Instruction>(*IU);
        if (!instUser) continue;
        if (!instUser->getParent()) continue;
        if (llvm::Function* userFunc = instUser->getParent()->getParent())
          funcsToFree.push_back(userFunc);
      }
    }
  }
  for (llvm::SmallPtrSet<llvm::Function*, 40>::iterator
         I = funcsToFreeUnique.begin(), E = funcsToFreeUnique.end();
       I != E; ++I) {
    // This should force the JIT to recompile the function. But the stubs stay,
    // and the JIT reuses the stubs now pointing nowhere, i.e. without updating
    // the machine code address. Fix the JIT, or hope that MCJIT helps.
    //engine->freeMachineCodeForFunction(*I);
    engine->updateGlobalMapping(*I, 0);
  }
}
#endif

IncrementalExecutor::ExecutionResult
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
  llvm::Module* m = T.getModule();
  assert(m && "Module must not be null");

  // Set m_CurrentAtExitModule to the Module, unset to 0 once done.
  struct AtExitModuleSetterRAII {
    llvm::Module*& m_AEM;
    AtExitModuleSetterRAII(llvm::Module* M, llvm::Module*& AEM): m_AEM(AEM)
    { AEM = M; }
    ~AtExitModuleSetterRAII() { m_AEM = 0; }
  } DSOHandleSetter(m, m_CurrentAtExitModule);

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  // check if there is any unresolved symbol in the list
  if (diagnoseUnresolvedSymbols("static initializers"))
    return kExeUnresolvedSymbols;

  llvm::GlobalVariable* GV
     = m->getGlobalVariable("llvm.global_ctors", true);
  // Nothing to do is good, too.
  if (!GV) return kExeSuccess;

  // Close similarity to
  // m_engine->runStaticConstructorsDestructors(false) aka
  // llvm::ExecutionEngine::runStaticConstructorsDestructors()
  // is intentional; we do an extra pass to check whether the JIT
  // managed to collect all the symbols needed by the niitializers.
  // Should be an array of '{ i32, void ()* }' structs.  The first value is
  // the init priority, which we ignore.
  llvm::ConstantArray *InitList
    = llvm::dyn_cast<llvm::ConstantArray>(GV->getInitializer());

  // We need to delete it here just in case we have recursive inits, otherwise
  // it will call inits multiple times.
  GV->eraseFromParent();

  if (InitList == 0)
    return kExeSuccess;

  SmallVector<Function*, 2> initFuncs;

  for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
    llvm::ConstantStruct *CS
      = llvm::dyn_cast<llvm::ConstantStruct>(InitList->getOperand(i));
    if (CS == 0) continue;

    llvm::Constant *FP = CS->getOperand(1);
    if (FP->isNullValue())
      continue;  // Found a sentinal value, ignore.

    // Strip off constant expression casts.
    if (llvm::ConstantExpr *CE = llvm::dyn_cast<llvm::ConstantExpr>(FP))
      if (CE->isCast())
        FP = CE->getOperand(0);

    // Execute the ctor/dtor function!
    if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
      executeInit(F->getName());

      initFuncs.push_back(F);
      if (F->getName().startswith("_GLOBAL__sub_I__")) {
        BasicBlock& BB = F->getEntryBlock();
        for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
          if (CallInst* call = dyn_cast<CallInst>(I))
            initFuncs.push_back(call->getCalledFunction());
      }
    }
  }

  for (SmallVector<Function*,2>::iterator I = initFuncs.begin(),
         E = initFuncs.end(); I != E; ++I) {
    // Cleanup also the dangling init functions. They are in the form:
    // define internal void @_GLOBAL__I_aN() section "..."{
    // entry:
    //   call void @__cxx_global_var_init(N-1)()
    //   call void @__cxx_global_var_initM()
    //   ret void
    // }
    //
    // define internal void @__cxx_global_var_init(N-1)() section "..." {
    // entry:
    //   call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
    //   ret void
    // }

    // Erase __cxx_global_var_init(N-1)() first.
    (*I)->removeDeadConstantUsers();
    (*I)->eraseFromParent();
  }

  return kExeSuccess;
}

void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) {
  assert(T && "Must be set");
  // Collect all the dtors bound to this transaction.
  AtExitFunctions boundToT;

  {
    cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
    for (AtExitFunctions::iterator I = m_AtExitFuncs.begin();
         I != m_AtExitFuncs.end();)
      if (I->m_FromM == T->getModule()) {
        boundToT.push_back(*I);
        I = m_AtExitFuncs.erase(I);
      }
      else
        ++I;
  } // end of spin lock lifetime block.

  // 'Unload' the cxa_atexit entities.
  for (AtExitFunctions::reverse_iterator I = boundToT.rbegin(),
         E = boundToT.rend(); I != E; ++I) {
    const CXAAtExitElement& AEE = *I;
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void
IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool
IncrementalExecutor::addSymbol(const char* symbolName,  void* symbolAddress) {
  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
                                              bool* fromJIT /*=0*/) {
  // Return a symbol's address, and whether it was jitted.
  void* address
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);

  // It's not from the JIT if it's in a dylib.
  if (fromJIT)
    *fromJIT = !address;

  if (!address)
    return (void*)m_JIT->getSymbolAddress(symbolName);

  return address;
}

void*
IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
  // Get the function / variable pointer referenced by GV.

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());

  if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
    return 0;
  return addr;
}

bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
                                                    llvm::StringRef title) {
  if (m_unresolvedSymbols.empty())
    return false;

  llvm::SmallVector<llvm::Function*, 128> funcsToFree;
  for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
         e = m_unresolvedSymbols.end(); i != e; ++i) {
#if 0
    // FIXME: This causes a lot of test failures, for some reason it causes
    // the call to HandleMissingFunction to be elided.
    unsigned diagID = m_Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                              "%0 unresolved while jitting %1");
    (void)diagID;
    //m_Diags.Report(diagID) << *i << funcname; // TODO: demangle the names.
#endif

    llvm::errs() << "IncrementalExecutor::executeFunction: symbol '" << *i
                 << "' unresolved while linking ";
    if (trigger.find(utils::Synthesize::UniquePrefix) != llvm::StringRef::npos)
      llvm::errs() << "[cling interface function]";
    else {
      if (!title.empty())
        llvm::errs() << title << " '";
      llvm::errs() << trigger;
      if (!title.empty())
        llvm::errs() << "'";
    }
    llvm::errs() << "!\n";

    // Be helpful, demangle!
    std::string demangledName;
    {
#ifndef LLVM_ON_WIN32
      int status = 0;
      char *demang = abi::__cxa_demangle(i->c_str(), 0, 0, &status);
      if (status == 0)
        demangledName = demang;
      free(demang);
#else
      if (char* demang = __unDName(0, i->c_str(), 0, malloc, free, 0)) {
        demangledName = demang;
        free(demang);
      }
#endif
    }
    if (!demangledName.empty()) {
       llvm::errs()
          << "You are probably missing the definition of "
          << demangledName << "\n"
          << "Maybe you need to load the corresponding shared library?\n";
    }

    //llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
    // i could also reference a global variable, in which case ff == 0.
    //if (ff)
    //  funcsToFree.push_back(ff);
  }
  //freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
  m_unresolvedSymbols.clear();
  return true;
}

}// end namespace cling
<commit_msg>Correct the name of bundle function of global initializer.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalExecutor.h"
#include "IncrementalJIT.h"
#include "Threading.h"

#include "cling/Interpreter/Value.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/Basic/Diagnostic.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"

#ifdef LLVM_ON_WIN32
extern "C"
char *__unDName(char *demangled, const char *mangled, int out_len,
                void * (* pAlloc )(size_t), void (* pFree )(void *),
                unsigned short int flags);
#else
#include <cxxabi.h>
#endif

using namespace llvm;

namespace cling {

IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags):
  m_CurrentAtExitModule(0)
#if 0
  : m_Diags(diags)
#endif
{

  // MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
  std::atomic_flag_clear( &m_AtExitFuncsSpinLock );

  // No need to protect this access of m_AtExitFuncs, since nobody
  // can use this object yet.
  m_AtExitFuncs.reserve(256);

  m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
}

// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
IncrementalExecutor::~IncrementalExecutor() {}

std::unique_ptr<TargetMachine>
  IncrementalExecutor::CreateHostTargetMachine() const {
  // TODO: make this configurable.
  Triple TheTriple(sys::getProcessTriple());
#ifdef _WIN32
  /*
	* MCJIT works on Windows, but currently only through ELF object format.
	*/
  TheTriple.setObjectFormat(llvm::Triple::ELF);
#endif
  std::string Error;
  const Target *TheTarget
    = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
  if (!TheTarget) {
    llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
                 << Error;
  }

  std::string MCPU;
  std::string FeaturesStr;

  TargetOptions Options = TargetOptions();
  Options.NoFramePointerElim = 1;
  Options.JITEmitDebugInfo = 1;
  Reloc::Model RelocModel = Reloc::Default;
  CodeModel::Model CMModel = CodeModel::JITDefault;
  CodeGenOpt::Level OptLevel = CodeGenOpt::Less;

  std::unique_ptr<TargetMachine> TM;
  TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
                                          MCPU, FeaturesStr,
                                          Options,
                                          RelocModel, CMModel,
                                          OptLevel));
  return std::move(TM);
}

void IncrementalExecutor::shuttingDown() {
  // No need to protect this access, since hopefully there is no concurrent
  // shutdown request.
  for (size_t I = 0, N = m_AtExitFuncs.size(); I < N; ++I) {
    const CXAAtExitElement& AEE = m_AtExitFuncs[N - I - 1];
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) {
  // Register a CXAAtExit function
  cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
  m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule));
}

void unresolvedSymbol()
{
  // This might get called recursively, or a billion of times. Do not generate
  // useless output; unresolvedSymbol() is always handed out with an error
  // message - that's enough.
  //llvm::errs() << "IncrementalExecutor: calling unresolved symbol, "
  //  "see previous error message!\n";

  // throw exception instead?
}

void* IncrementalExecutor::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    //llvm::errs() << "IncrementalExecutor: use of undefined symbol '"
    //             << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
IncrementalExecutor::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  return HandleMissingFunction(mangled_name);
}

#if 0
// FIXME: employ to empty module dependencies *within* the *current* module.
static void
freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
                               funcsToFree, llvm::ExecutionEngine* engine) {
  llvm::SmallPtrSet<llvm::Function*, 40> funcsToFreeUnique;
  for (size_t i = 0; i < funcsToFree.size(); ++i) {
    llvm::Function* func = funcsToFree[i];
    assert(func && "Cannot free NULL function");
    if (funcsToFreeUnique.insert(func).second) {
      for (llvm::Value::use_iterator IU = func->use_begin(),
             EU = func->use_end(); IU != EU; ++IU) {
        llvm::Instruction* instUser = llvm::dyn_cast<llvm::Instruction>(*IU);
        if (!instUser) continue;
        if (!instUser->getParent()) continue;
        if (llvm::Function* userFunc = instUser->getParent()->getParent())
          funcsToFree.push_back(userFunc);
      }
    }
  }
  for (llvm::SmallPtrSet<llvm::Function*, 40>::iterator
         I = funcsToFreeUnique.begin(), E = funcsToFreeUnique.end();
       I != E; ++I) {
    // This should force the JIT to recompile the function. But the stubs stay,
    // and the JIT reuses the stubs now pointing nowhere, i.e. without updating
    // the machine code address. Fix the JIT, or hope that MCJIT helps.
    //engine->freeMachineCodeForFunction(*I);
    engine->updateGlobalMapping(*I, 0);
  }
}
#endif

IncrementalExecutor::ExecutionResult
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
  llvm::Module* m = T.getModule();
  assert(m && "Module must not be null");

  // Set m_CurrentAtExitModule to the Module, unset to 0 once done.
  struct AtExitModuleSetterRAII {
    llvm::Module*& m_AEM;
    AtExitModuleSetterRAII(llvm::Module* M, llvm::Module*& AEM): m_AEM(AEM)
    { AEM = M; }
    ~AtExitModuleSetterRAII() { m_AEM = 0; }
  } DSOHandleSetter(m, m_CurrentAtExitModule);

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  // check if there is any unresolved symbol in the list
  if (diagnoseUnresolvedSymbols("static initializers"))
    return kExeUnresolvedSymbols;

  llvm::GlobalVariable* GV
     = m->getGlobalVariable("llvm.global_ctors", true);
  // Nothing to do is good, too.
  if (!GV) return kExeSuccess;

  // Close similarity to
  // m_engine->runStaticConstructorsDestructors(false) aka
  // llvm::ExecutionEngine::runStaticConstructorsDestructors()
  // is intentional; we do an extra pass to check whether the JIT
  // managed to collect all the symbols needed by the niitializers.
  // Should be an array of '{ i32, void ()* }' structs.  The first value is
  // the init priority, which we ignore.
  llvm::ConstantArray *InitList
    = llvm::dyn_cast<llvm::ConstantArray>(GV->getInitializer());

  // We need to delete it here just in case we have recursive inits, otherwise
  // it will call inits multiple times.
  GV->eraseFromParent();

  if (InitList == 0)
    return kExeSuccess;

  SmallVector<Function*, 2> initFuncs;

  for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
    llvm::ConstantStruct *CS
      = llvm::dyn_cast<llvm::ConstantStruct>(InitList->getOperand(i));
    if (CS == 0) continue;

    llvm::Constant *FP = CS->getOperand(1);
    if (FP->isNullValue())
      continue;  // Found a sentinal value, ignore.

    // Strip off constant expression casts.
    if (llvm::ConstantExpr *CE = llvm::dyn_cast<llvm::ConstantExpr>(FP))
      if (CE->isCast())
        FP = CE->getOperand(0);

    // Execute the ctor/dtor function!
    if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
      executeInit(F->getName());

      initFuncs.push_back(F);
      if (F->getName().startswith("_GLOBAL__sub_I_")) {
        BasicBlock& BB = F->getEntryBlock();
        for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
          if (CallInst* call = dyn_cast<CallInst>(I))
            initFuncs.push_back(call->getCalledFunction());
      }
    }
  }

  for (SmallVector<Function*,2>::iterator I = initFuncs.begin(),
         E = initFuncs.end(); I != E; ++I) {
    // Cleanup also the dangling init functions. They are in the form:
    // define internal void @_GLOBAL__I_aN() section "..."{
    // entry:
    //   call void @__cxx_global_var_init(N-1)()
    //   call void @__cxx_global_var_initM()
    //   ret void
    // }
    //
    // define internal void @__cxx_global_var_init(N-1)() section "..." {
    // entry:
    //   call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
    //   ret void
    // }

    // Erase __cxx_global_var_init(N-1)() first.
    (*I)->removeDeadConstantUsers();
    (*I)->eraseFromParent();
  }

  return kExeSuccess;
}

void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) {
  assert(T && "Must be set");
  // Collect all the dtors bound to this transaction.
  AtExitFunctions boundToT;

  {
    cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
    for (AtExitFunctions::iterator I = m_AtExitFuncs.begin();
         I != m_AtExitFuncs.end();)
      if (I->m_FromM == T->getModule()) {
        boundToT.push_back(*I);
        I = m_AtExitFuncs.erase(I);
      }
      else
        ++I;
  } // end of spin lock lifetime block.

  // 'Unload' the cxa_atexit entities.
  for (AtExitFunctions::reverse_iterator I = boundToT.rbegin(),
         E = boundToT.rend(); I != E; ++I) {
    const CXAAtExitElement& AEE = *I;
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void
IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool
IncrementalExecutor::addSymbol(const char* symbolName,  void* symbolAddress) {
  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
                                              bool* fromJIT /*=0*/) {
  // Return a symbol's address, and whether it was jitted.
  void* address
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);

  // It's not from the JIT if it's in a dylib.
  if (fromJIT)
    *fromJIT = !address;

  if (!address)
    return (void*)m_JIT->getSymbolAddress(symbolName);

  return address;
}

void*
IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
  // Get the function / variable pointer referenced by GV.

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());

  if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
    return 0;
  return addr;
}

bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
                                                    llvm::StringRef title) {
  if (m_unresolvedSymbols.empty())
    return false;

  llvm::SmallVector<llvm::Function*, 128> funcsToFree;
  for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
         e = m_unresolvedSymbols.end(); i != e; ++i) {
#if 0
    // FIXME: This causes a lot of test failures, for some reason it causes
    // the call to HandleMissingFunction to be elided.
    unsigned diagID = m_Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                              "%0 unresolved while jitting %1");
    (void)diagID;
    //m_Diags.Report(diagID) << *i << funcname; // TODO: demangle the names.
#endif

    llvm::errs() << "IncrementalExecutor::executeFunction: symbol '" << *i
                 << "' unresolved while linking ";
    if (trigger.find(utils::Synthesize::UniquePrefix) != llvm::StringRef::npos)
      llvm::errs() << "[cling interface function]";
    else {
      if (!title.empty())
        llvm::errs() << title << " '";
      llvm::errs() << trigger;
      if (!title.empty())
        llvm::errs() << "'";
    }
    llvm::errs() << "!\n";

    // Be helpful, demangle!
    std::string demangledName;
    {
#ifndef LLVM_ON_WIN32
      int status = 0;
      char *demang = abi::__cxa_demangle(i->c_str(), 0, 0, &status);
      if (status == 0)
        demangledName = demang;
      free(demang);
#else
      if (char* demang = __unDName(0, i->c_str(), 0, malloc, free, 0)) {
        demangledName = demang;
        free(demang);
      }
#endif
    }
    if (!demangledName.empty()) {
       llvm::errs()
          << "You are probably missing the definition of "
          << demangledName << "\n"
          << "Maybe you need to load the corresponding shared library?\n";
    }

    //llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
    // i could also reference a global variable, in which case ff == 0.
    //if (ff)
    //  funcsToFree.push_back(ff);
  }
  //freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
  m_unresolvedSymbols.clear();
  return true;
}

}// end namespace cling
<|endoftext|>