<commit_before>#include <clang-c/Index.h>

#include <array>
#include <iostream>
#include <vector>

namespace {

    const unsigned int indent_spaces = 4;
    const std::string indentation(indent_spaces, ' ');

}

CXCursor tu_cursor;

struct client_data
{
    CXTranslationUnit tu;
    std::vector<CXCursor> current_namespaces;
    CXCursor current_struct;
    // function signature, forwarding call arguments, optional return
    // keyword, and function name
    std::vector<std::array<std::string, 4>> member_functions;
    bool printed_headers;
    const char* filename;
};

std::pair<CXToken*, unsigned int>
get_tokens (CXTranslationUnit tu, CXCursor cursor)
{
    CXSourceRange range = clang_getCursorExtent(cursor);
    CXSourceLocation start = clang_getRangeStart(range);
    CXSourceLocation end = clang_getRangeEnd(range);
    unsigned int start_offset, end_offset;

    std::pair<CXToken*, unsigned int> retval(0, 0);
    clang_tokenize(tu, range, &retval.first, &retval.second);

    return retval;
}

void
free_tokens (CXTranslationUnit tu, std::pair<CXToken*, unsigned int> tokens)
{ clang_disposeTokens(tu, tokens.first, tokens.second); }

void print_tokens (CXTranslationUnit tu, CXCursor cursor, bool elide_final_token)
{
    std::pair<CXToken*, unsigned int> tokens = get_tokens(tu, cursor);

    const unsigned int num_tokens =
        tokens.second && elide_final_token ? tokens.second - 1 : tokens.second;
    for (unsigned int i = 0; i < num_tokens; ++i) {
        if (i)
            std::cout << " ";
        CXString spelling = clang_getTokenSpelling(tu, tokens.first[i]);
        std::cout << clang_getCString(spelling);
    }
    std::cout << "\n";

    free_tokens(tu, tokens);
}

bool struct_kind (CXCursorKind kind)
{
    switch (kind) {
    case CXCursor_ClassDecl:
    case CXCursor_StructDecl:
    case CXCursor_ClassTemplate:
    case CXCursor_ClassTemplatePartialSpecialization:
        return true;
    }
    return false;
}

std::string indent (const client_data & data)
{
    std::size_t size = data.current_namespaces.size();
    return std::string(size * indent_spaces, ' ');
}

void print_lines (const client_data & data,
                  const char** lines,
                  std::size_t num_lines)
{
    for (unsigned int i = 0; i < num_lines; ++i) {
        if (lines[i])
            std::cout << indent(data) << indentation << lines[i] << "\n";
        else
            std::cout << "\n";
    }
}

void print_headers (client_data & data)
{
    if (data.printed_headers)
        return;

    std::cout << "#include <algorithm>\n"
              << "#include <functional>\n"
              << "#include <memory>\n"
              << "#include <type_traits>\n"
              << "#include <utility>\n"
              << "\n";

    data.printed_headers = true;
}

void open_struct (const client_data & data, CXCursor struct_cursor)
{
    std::pair<CXToken*, unsigned int> tokens =
        get_tokens(data.tu, struct_cursor);

    std::cout << "\n" << indent(data);

    const std::string open_brace = "{";
    const std::string struct_ = "struct";
    const std::string class_ = "class";

    for (unsigned int i = 0; i < tokens.second; ++i) {
        CXString spelling = clang_getTokenSpelling(data.tu, tokens.first[i]);

        const char* c_str = clang_getCString(spelling);

        if (c_str == open_brace)
            break;

        if (c_str == struct_ || c_str == class_) {
            std::cout << "\n" << indent(data);
        } else if (i) {
            std::cout << " ";
        }

        std::cout << c_str;
    }

    free_tokens(data.tu, tokens);

    const std::string struct_name =
        clang_getCString(clang_getCursorSpelling(data.current_struct));

    const std::string ctor_0 =
        struct_name + " () = default;";
    const std::string ctor_1 =
        struct_name + " (T_T__ value) :";
    const std::string ctor_2 =
        struct_name + " (any_printable && rhs) noexcept = default;";
    const std::string ctor_3 =
        struct_name + " & operator= (T_T__ value)";
    const std::string ctor_4 =
        struct_name + " & operator= (any_printable && rhs) noexcept = default;";

    std::cout << "\n"
              << indent(data) << "{\n"
              << indent(data) << "public:\n";

    const char* public_interface[] = {
        0,
        ctor_0.c_str(),
        0,
        "template <typename T_T__>",
        ctor_1.c_str(),
        "    handle_ (",
        "        std::make_shared<",
        "            handle<typename std::remove_reference<T_T__>::type>",
        "        >(std::forward<T_T__>(value))",
        "    )",
        "{}",
        0,
        ctor_2.c_str(),
        0,
        "template <typename T_T__>",
        ctor_3.c_str(),
        "{",
        "    if (handle_.unique())",
        "        *handle_ = std::forward<T_T__>(value);",
        "    else if (!handle_)",
        "        handle_ = std::make_shared<T_T__>(std::forward<T_T__>(value));",
        "    return *this;",
        "}",
        0,
        ctor_4.c_str()
    };

    print_lines(data,
                public_interface,
                sizeof(public_interface) / sizeof(const char*));
}

void close_struct (const client_data & data)
{
    std::cout << "\n"
              << indent(data) << "private:\n";

    const char* handle_base_preamble[] = {
        0,
        "struct handle_base",
        "{",
        "    virtual ~handle_base () {}",
        "    virtual std::shared_ptr<handle_base> close () const = 0;",
        0
    };

    print_lines(data,
                handle_base_preamble,
                sizeof(handle_base_preamble) / sizeof(const char*));

    for (auto & member : data.member_functions) {
        std::cout << indent(data) << indentation << indentation
                  << "virtual " << member[0] << " = 0;\n";
    }

    const char* handle_preamble[] = {
        0,
        "};",
        0,
        "template <typename T_T__>",
        "struct handle :",
        "    handle_base",
        "{",
        "    template <typename T_T__>",
        "    handle (T_T__ value,",
        "            typename std::enable_if<",
        "                std::is_reference<U_U__>::value",
        "            >::type* = 0) :",
        "        value_ (value)",
        "    {}",
        0,
        "    template <typename U_U__ = T_T__>",
        "    handle (T_T__ value,",
        "            typename std::enable_if<",
        "                !std::is_reference<U_U__>::value,",
        "                int",
        "            >::type* = 0) noexcept :",
        "        value_ (std::move(value))",
        "    {}",
        0,
        "    virtual std::shared_ptr<handle_base> clone () const",
        "    { return std::make_shared<handle>(value_); }"
    };

    print_lines(data,
                handle_preamble,
                sizeof(handle_preamble) / sizeof(const char*));

    for (auto & member : data.member_functions) {
        std::cout << "\n"
                  << indent(data) << indentation << indentation
                  << "virtual " << member[0] << "\n"
                  << indent(data) << indentation << indentation
                  << "{ " << member[2] << "value_." << member[3]
                  << "( " << member[1] << " ); }\n";
    }

    const char* handle_postamble[] = {
        0,
        "    T_T__ value_;",
        "};",
        0,
        "template <typename T_T__>",
        "struct handle<std::reference_wrapper<T_T__>> :",
        "    handle<T_T__ &>",
        "{",
        "    handle (std::reference_wrapper<T_T__> ref) :",
        "        handle<T_T__ &> (ref.get())",
        "    {}",
        "};",
        0,
        "const handle_base & read () const",
        "{ return *handle_; }",
        0,
        "handle_base & write ()",
        "{",
        "    if (!handle_.unique())",
        "        handle_ = handle_->clone();",
        "    return *handle_;",
        "}",
        0,
        "std::shared_ptr<handle_base> handle_;"
    };

    print_lines(data,
                handle_postamble,
                sizeof(handle_postamble) / sizeof(const char*));

    std::cout << "\n"
              << indent(data) << "};\n";
}

void print_member_function (const client_data & data, CXCursor cursor)
{
    std::cout << "\n"
              << std::string(indent_spaces, ' ') << indent(data)
              << data.member_functions.back()[0];

    std::cout << "\n" << std::string(indent_spaces, ' ') << indent(data)
              << "{ assert(handle_); " << data.member_functions.back()[2]
              << "handle_->"
              << clang_getCString(clang_getCursorSpelling(cursor))
              << "( " << data.member_functions.back()[1] << " ); }\n";
}

void open_namespace (const client_data & data, CXCursor namespace_)
{
    std::cout
        << "\n"
        << indent(data)
        << "namespace "
        << clang_getCString(clang_getCursorSpelling(namespace_))
        << " {";
}

void close_namespace (const client_data & data)
{ std::cout << "\n" << indent(data) << "}\n"; }

CXChildVisitResult
visitor (CXCursor cursor, CXCursor parent, CXClientData data_)
{
    client_data & data = *static_cast<client_data*>(data_);

    CXCursor null_cursor = clang_getNullCursor();

    // close open namespaces we have left
    CXCursor enclosing_namespace = parent;
    while (!clang_equalCursors(enclosing_namespace, tu_cursor) &&
           clang_getCursorKind(enclosing_namespace) != CXCursor_Namespace) {
        enclosing_namespace =
            clang_getCursorSemanticParent(enclosing_namespace);
    }
    if (!clang_equalCursors(enclosing_namespace, tu_cursor) &&
        clang_getCursorKind(enclosing_namespace) == CXCursor_Namespace) {
        while (!data.current_namespaces.empty() &&
               !clang_equalCursors(enclosing_namespace,
                                   data.current_namespaces.back())) {
            data.current_namespaces.pop_back();
            close_namespace(data);
        }
    }

    // close open struct if we have left it
    CXCursor enclosing_struct = parent;
    while (!clang_equalCursors(enclosing_struct, tu_cursor) &&
           !struct_kind(clang_getCursorKind(enclosing_struct))) {
        enclosing_struct = clang_getCursorSemanticParent(enclosing_struct);
    }
    if (!clang_Cursor_isNull(data.current_struct) &&
        !clang_equalCursors(enclosing_struct, data.current_struct)) {
        data.current_struct = null_cursor;
        close_struct(data);
        data.member_functions.clear();
    }

    CXSourceLocation location = clang_getCursorLocation(cursor);
    const bool from_main_file = clang_Location_isFromMainFile(location);

    CXCursorKind kind = clang_getCursorKind(cursor);
    if (kind == CXCursor_Namespace) {
        if (from_main_file) {
            print_headers(data);
            open_namespace(data, cursor);
            data.current_namespaces.push_back(cursor);
        }
        return CXChildVisit_Recurse;
    } else if (!from_main_file) {
        return CXChildVisit_Continue;
    } else if (struct_kind(kind)) {
        if (clang_Cursor_isNull(data.current_struct)) {
            print_headers(data);
            data.current_struct = cursor;
            open_struct(data, cursor);
            return CXChildVisit_Recurse;
        }
    } else if (kind == CXCursor_CXXMethod) {
        std::pair<CXToken*, unsigned int> tokens = get_tokens(data.tu, cursor);

        const std::string open_brace = "{";
        const std::string semicolon = ";";

        std::string str;

        for (unsigned int i = 0; i < tokens.second; ++i) {
            CXString spelling =
                clang_getTokenSpelling(data.tu, tokens.first[i]);

            const char* c_str = clang_getCString(spelling);

            if (c_str == open_brace || c_str == semicolon)
                break;

            if (i)
                str += " ";

            str += c_str;
        }

        std::string args;

        const int num_args = clang_Cursor_getNumArguments(cursor);
        for (int i = 0; i < num_args; ++i) {
            if (i)
                args += ", ";
            CXCursor arg_cursor = clang_Cursor_getArgument(cursor, i);
            args += clang_getCString(clang_getCursorSpelling(arg_cursor));
        }

        const char* return_str =
            clang_getCursorResultType(cursor).kind == CXType_Void ?
            "" :
            "return ";

        const char* function_name =
            clang_getCString(clang_getCursorSpelling(cursor));

        free_tokens(data.tu, tokens);

        data.member_functions.push_back({str, args, return_str, function_name});

        print_member_function(data, cursor);
    }

    return CXChildVisit_Continue;
}

CXVisitorResult visit_includes (void * context, CXCursor cursor, CXSourceRange range)
{
    print_tokens(static_cast<CXTranslationUnit>(context), cursor, true);
    return CXVisit_Continue;
}

int main (int argc, char* argv[])
{
    CXIndex index = clang_createIndex(0, 1);
    CXTranslationUnit tu = clang_parseTranslationUnit(
        index,
        0,
        argv,
        argc,
        0,
        0,
        CXTranslationUnit_DetailedPreprocessingRecord
    );

    const char* filename =
        clang_getCString(clang_getTranslationUnitSpelling(tu));

    CXFile file = clang_getFile(tu, filename);
    CXCursorAndRangeVisitor visitor_ = {tu, visit_includes};
    clang_findIncludesInFile(tu, file, visitor_);
    std::cout << "\n";

    client_data data = {tu, {}, clang_getNullCursor(), {}, false, filename};

    tu_cursor = clang_getTranslationUnitCursor(tu);
    clang_visitChildren(tu_cursor, visitor, &data);

    if (!clang_Cursor_isNull(data.current_struct))
        close_struct(data);

    while (!data.current_namespaces.empty()) {
        data.current_namespaces.pop_back();
        close_namespace(data);
    }

    clang_disposeTranslationUnit(tu);
    clang_disposeIndex(index);

    return 0;
}
<commit_msg>Preserve include guards on input header, if any.<commit_after>#include <clang-c/Index.h>

#include <array>
#include <iostream>
#include <vector>

namespace {

    const unsigned int indent_spaces = 4;
    const std::string indentation(indent_spaces, ' ');

}

CXCursor tu_cursor;

struct client_data
{
    CXTranslationUnit tu;
    std::vector<CXCursor> current_namespaces;
    CXCursor current_struct;
    // function signature, forwarding call arguments, optional return
    // keyword, and function name
    std::vector<std::array<std::string, 4>> member_functions;
    bool printed_headers;
    const char* filename;
    bool include_guarded;
};

std::pair<CXToken*, unsigned int>
get_tokens (CXTranslationUnit tu, CXCursor cursor)
{
    CXSourceRange range = clang_getCursorExtent(cursor);
    CXSourceLocation start = clang_getRangeStart(range);
    CXSourceLocation end = clang_getRangeEnd(range);
    unsigned int start_offset, end_offset;

    std::pair<CXToken*, unsigned int> retval(0, 0);
    clang_tokenize(tu, range, &retval.first, &retval.second);

    return retval;
}

void
free_tokens (CXTranslationUnit tu, std::pair<CXToken*, unsigned int> tokens)
{ clang_disposeTokens(tu, tokens.first, tokens.second); }

void print_tokens (CXTranslationUnit tu, CXCursor cursor, bool elide_final_token)
{
    std::pair<CXToken*, unsigned int> tokens = get_tokens(tu, cursor);

    const unsigned int num_tokens =
        tokens.second && elide_final_token ? tokens.second - 1 : tokens.second;
    for (unsigned int i = 0; i < num_tokens; ++i) {
        if (i)
            std::cout << " ";
        CXString spelling = clang_getTokenSpelling(tu, tokens.first[i]);
        std::cout << clang_getCString(spelling);
    }
    std::cout << "\n";

    free_tokens(tu, tokens);
}

bool struct_kind (CXCursorKind kind)
{
    switch (kind) {
    case CXCursor_ClassDecl:
    case CXCursor_StructDecl:
    case CXCursor_ClassTemplate:
    case CXCursor_ClassTemplatePartialSpecialization:
        return true;
    default:
        return false;
    }
    return false;
}

std::string indent (const client_data & data)
{
    std::size_t size = data.current_namespaces.size();
    return std::string(size * indent_spaces, ' ');
}

void print_lines (const client_data & data,
                  const char** lines,
                  std::size_t num_lines)
{
    for (unsigned int i = 0; i < num_lines; ++i) {
        if (lines[i])
            std::cout << indent(data) << indentation << lines[i] << "\n";
        else
            std::cout << "\n";
    }
}

void print_headers (client_data & data)
{
    if (data.printed_headers)
        return;

    std::cout << "#include <algorithm>\n"
              << "#include <functional>\n"
              << "#include <memory>\n"
              << "#include <type_traits>\n"
              << "#include <utility>\n"
              << "\n";

    data.printed_headers = true;
}

void open_struct (const client_data & data, CXCursor struct_cursor)
{
    std::pair<CXToken*, unsigned int> tokens =
        get_tokens(data.tu, struct_cursor);

    std::cout << "\n" << indent(data);

    const std::string open_brace = "{";
    const std::string struct_ = "struct";
    const std::string class_ = "class";

    for (unsigned int i = 0; i < tokens.second; ++i) {
        CXString spelling = clang_getTokenSpelling(data.tu, tokens.first[i]);

        const char* c_str = clang_getCString(spelling);

        if (c_str == open_brace)
            break;

        if (c_str == struct_ || c_str == class_) {
            std::cout << "\n" << indent(data);
        } else if (i) {
            std::cout << " ";
        }

        std::cout << c_str;
    }

    free_tokens(data.tu, tokens);

    const std::string struct_name =
        clang_getCString(clang_getCursorSpelling(data.current_struct));

    const std::string ctor_0 =
        struct_name + " () = default;";
    const std::string ctor_1 =
        struct_name + " (T_T__ value) :";
    const std::string ctor_2 =
        struct_name + " (any_printable && rhs) noexcept = default;";
    const std::string ctor_3 =
        struct_name + " & operator= (T_T__ value)";
    const std::string ctor_4 =
        struct_name + " & operator= (any_printable && rhs) noexcept = default;";

    std::cout << "\n"
              << indent(data) << "{\n"
              << indent(data) << "public:\n";

    const char* public_interface[] = {
        0,
        ctor_0.c_str(),
        0,
        "template <typename T_T__>",
        ctor_1.c_str(),
        "    handle_ (",
        "        std::make_shared<",
        "            handle<typename std::remove_reference<T_T__>::type>",
        "        >(std::forward<T_T__>(value))",
        "    )",
        "{}",
        0,
        ctor_2.c_str(),
        0,
        "template <typename T_T__>",
        ctor_3.c_str(),
        "{",
        "    if (handle_.unique())",
        "        *handle_ = std::forward<T_T__>(value);",
        "    else if (!handle_)",
        "        handle_ = std::make_shared<T_T__>(std::forward<T_T__>(value));",
        "    return *this;",
        "}",
        0,
        ctor_4.c_str()
    };

    print_lines(data,
                public_interface,
                sizeof(public_interface) / sizeof(const char*));
}

void close_struct (const client_data & data)
{
    std::cout << "\n"
              << indent(data) << "private:\n";

    const char* handle_base_preamble[] = {
        0,
        "struct handle_base",
        "{",
        "    virtual ~handle_base () {}",
        "    virtual std::shared_ptr<handle_base> close () const = 0;",
        0
    };

    print_lines(data,
                handle_base_preamble,
                sizeof(handle_base_preamble) / sizeof(const char*));

    for (auto & member : data.member_functions) {
        std::cout << indent(data) << indentation << indentation
                  << "virtual " << member[0] << " = 0;\n";
    }

    const char* handle_preamble[] = {
        0,
        "};",
        0,
        "template <typename T_T__>",
        "struct handle :",
        "    handle_base",
        "{",
        "    template <typename T_T__>",
        "    handle (T_T__ value,",
        "            typename std::enable_if<",
        "                std::is_reference<U_U__>::value",
        "            >::type* = 0) :",
        "        value_ (value)",
        "    {}",
        0,
        "    template <typename U_U__ = T_T__>",
        "    handle (T_T__ value,",
        "            typename std::enable_if<",
        "                !std::is_reference<U_U__>::value,",
        "                int",
        "            >::type* = 0) noexcept :",
        "        value_ (std::move(value))",
        "    {}",
        0,
        "    virtual std::shared_ptr<handle_base> clone () const",
        "    { return std::make_shared<handle>(value_); }"
    };

    print_lines(data,
                handle_preamble,
                sizeof(handle_preamble) / sizeof(const char*));

    for (auto & member : data.member_functions) {
        std::cout << "\n"
                  << indent(data) << indentation << indentation
                  << "virtual " << member[0] << "\n"
                  << indent(data) << indentation << indentation
                  << "{ " << member[2] << "value_." << member[3]
                  << "( " << member[1] << " ); }\n";
    }

    const char* handle_postamble[] = {
        0,
        "    T_T__ value_;",
        "};",
        0,
        "template <typename T_T__>",
        "struct handle<std::reference_wrapper<T_T__>> :",
        "    handle<T_T__ &>",
        "{",
        "    handle (std::reference_wrapper<T_T__> ref) :",
        "        handle<T_T__ &> (ref.get())",
        "    {}",
        "};",
        0,
        "const handle_base & read () const",
        "{ return *handle_; }",
        0,
        "handle_base & write ()",
        "{",
        "    if (!handle_.unique())",
        "        handle_ = handle_->clone();",
        "    return *handle_;",
        "}",
        0,
        "std::shared_ptr<handle_base> handle_;"
    };

    print_lines(data,
                handle_postamble,
                sizeof(handle_postamble) / sizeof(const char*));

    std::cout << "\n"
              << indent(data) << "};\n";
}

void print_member_function (const client_data & data, CXCursor cursor)
{
    std::cout << "\n"
              << std::string(indent_spaces, ' ') << indent(data)
              << data.member_functions.back()[0];

    std::cout << "\n" << std::string(indent_spaces, ' ') << indent(data)
              << "{ assert(handle_); " << data.member_functions.back()[2]
              << "handle_->"
              << clang_getCString(clang_getCursorSpelling(cursor))
              << "( " << data.member_functions.back()[1] << " ); }\n";
}

void open_namespace (const client_data & data, CXCursor namespace_)
{
    std::cout
        << "\n"
        << indent(data)
        << "namespace "
        << clang_getCString(clang_getCursorSpelling(namespace_))
        << " {";
}

void close_namespace (const client_data & data)
{ std::cout << "\n" << indent(data) << "}\n"; }

CXChildVisitResult
visit_preprocessor_defines (CXCursor cursor, CXCursor parent, CXClientData data_)
{
    client_data & data = *static_cast<client_data*>(data_);

    if (!data.include_guarded)
        return CXChildVisit_Break;

    CXSourceLocation location = clang_getCursorLocation(cursor);
    const bool from_main_file = clang_Location_isFromMainFile(location);

    CXCursorKind kind = clang_getCursorKind(cursor);
    if (!from_main_file) {
        return CXChildVisit_Continue;
    } else if (kind == CXCursor_MacroDefinition) {
        const char* guard = clang_getCString(clang_getCursorSpelling(cursor));
        std::cout << "#ifndef " << guard << "\n"
                  << "#define " << guard << "\n"
                  << "\n";
        return CXChildVisit_Break;
    }
    return CXChildVisit_Recurse;
}

CXChildVisitResult
visit (CXCursor cursor, CXCursor parent, CXClientData data_)
{
    client_data & data = *static_cast<client_data*>(data_);

    CXCursor null_cursor = clang_getNullCursor();

    // close open namespaces we have left
    CXCursor enclosing_namespace = parent;
    while (!clang_equalCursors(enclosing_namespace, tu_cursor) &&
           clang_getCursorKind(enclosing_namespace) != CXCursor_Namespace) {
        enclosing_namespace =
            clang_getCursorSemanticParent(enclosing_namespace);
    }
    if (!clang_equalCursors(enclosing_namespace, tu_cursor) &&
        clang_getCursorKind(enclosing_namespace) == CXCursor_Namespace) {
        while (!data.current_namespaces.empty() &&
               !clang_equalCursors(enclosing_namespace,
                                   data.current_namespaces.back())) {
            data.current_namespaces.pop_back();
            close_namespace(data);
        }
    }

    // close open struct if we have left it
    CXCursor enclosing_struct = parent;
    while (!clang_equalCursors(enclosing_struct, tu_cursor) &&
           !struct_kind(clang_getCursorKind(enclosing_struct))) {
        enclosing_struct = clang_getCursorSemanticParent(enclosing_struct);
    }
    if (!clang_Cursor_isNull(data.current_struct) &&
        !clang_equalCursors(enclosing_struct, data.current_struct)) {
        data.current_struct = null_cursor;
        close_struct(data);
        data.member_functions.clear();
    }

    CXSourceLocation location = clang_getCursorLocation(cursor);
    const bool from_main_file = clang_Location_isFromMainFile(location);

    CXCursorKind kind = clang_getCursorKind(cursor);
    if (kind == CXCursor_Namespace) {
        if (from_main_file) {
            print_headers(data);
            open_namespace(data, cursor);
            data.current_namespaces.push_back(cursor);
        }
        return CXChildVisit_Recurse;
    } else if (!from_main_file) {
        return CXChildVisit_Continue;
    } else if (struct_kind(kind)) {
        if (clang_Cursor_isNull(data.current_struct)) {
            print_headers(data);
            data.current_struct = cursor;
            open_struct(data, cursor);
            return CXChildVisit_Recurse;
        }
    } else if (kind == CXCursor_CXXMethod) {
        std::pair<CXToken*, unsigned int> tokens = get_tokens(data.tu, cursor);

        const std::string open_brace = "{";
        const std::string semicolon = ";";

        std::string str;

        for (unsigned int i = 0; i < tokens.second; ++i) {
            CXString spelling =
                clang_getTokenSpelling(data.tu, tokens.first[i]);

            const char* c_str = clang_getCString(spelling);

            if (c_str == open_brace || c_str == semicolon)
                break;

            if (i)
                str += " ";

            str += c_str;
        }

        std::string args;

        const int num_args = clang_Cursor_getNumArguments(cursor);
        for (int i = 0; i < num_args; ++i) {
            if (i)
                args += ", ";
            CXCursor arg_cursor = clang_Cursor_getArgument(cursor, i);
            args += clang_getCString(clang_getCursorSpelling(arg_cursor));
        }

        const char* return_str =
            clang_getCursorResultType(cursor).kind == CXType_Void ?
            "" :
            "return ";

        const char* function_name =
            clang_getCString(clang_getCursorSpelling(cursor));

        free_tokens(data.tu, tokens);

        data.member_functions.push_back({str, args, return_str, function_name});

        print_member_function(data, cursor);
    }

    return CXChildVisit_Continue;
}

CXVisitorResult visit_includes (void * context, CXCursor cursor, CXSourceRange range)
{
    print_tokens(static_cast<CXTranslationUnit>(context), cursor, true);
    return CXVisit_Continue;
}

int main (int argc, char* argv[])
{
    CXIndex index = clang_createIndex(0, 1);
    CXTranslationUnit tu = clang_parseTranslationUnit(
        index,
        0,
        argv,
        argc,
        0,
        0,
        CXTranslationUnit_DetailedPreprocessingRecord
    );

    const char* filename =
        clang_getCString(clang_getTranslationUnitSpelling(tu));

    CXFile file = clang_getFile(tu, filename);

    const bool include_guarded = clang_isFileMultipleIncludeGuarded(tu, file);

    client_data data =
        {tu, {}, clang_getNullCursor(), {}, false, filename, include_guarded};

    tu_cursor = clang_getTranslationUnitCursor(tu);

    clang_visitChildren(tu_cursor, visit_preprocessor_defines, &data);

    CXCursorAndRangeVisitor visitor = {tu, visit_includes};
    clang_findIncludesInFile(tu, file, visitor);
    std::cout << "\n";

    clang_visitChildren(tu_cursor, visit, &data);

    if (!clang_Cursor_isNull(data.current_struct))
        close_struct(data);

    while (!data.current_namespaces.empty()) {
        data.current_namespaces.pop_back();
        close_namespace(data);
    }

    if (include_guarded)
        std::cout << "\n#endif\n";

    clang_disposeTranslationUnit(tu);
    clang_disposeIndex(index);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "PointerTest.h"

#include <decaf/lang/Pointer.h>
#include <decaf/lang/Thread.h>
#include <decaf/lang/Runnable.h>

#include <map>
#include <string>

using namespace std;
using namespace decaf;
using namespace decaf::lang;

////////////////////////////////////////////////////////////////////////////////
class TestClassBase {
public:

    virtual ~TestClassBase(){}

    virtual std::string returnHello() = 0;

};

////////////////////////////////////////////////////////////////////////////////
class TestClassA : public TestClassBase {
public:

    virtual ~TestClassA() {
        //std::cout << std::endl << "TestClassA - Destructor" << std::endl;
    }

    std::string returnHello() {
        return "Hello";
    }

};

////////////////////////////////////////////////////////////////////////////////
class TestClassB : public TestClassBase {
public:

    virtual ~TestClassB() {
        //std::cout << std::endl << "TestClassB - Destructor" << std::endl;
    }

    std::string returnHello() {
        return "GoodBye";
    }

};

////////////////////////////////////////////////////////////////////////////////
class SomeOtherClass {
public:

};

////////////////////////////////////////////////////////////////////////////////
struct X {
    Pointer<X> next;
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testBasics() {

    TestClassA* thePointer = new TestClassA();

    // Test Null Initialize
    Pointer<TestClassA> nullPointer;
    CPPUNIT_ASSERT( nullPointer.get() == NULL );

    // Test Value Constructor
    Pointer<TestClassA> pointer( thePointer );
    CPPUNIT_ASSERT( pointer.get() == thePointer );

    // Test Copy Constructor
    Pointer<TestClassA> ctorCopy( pointer );
    CPPUNIT_ASSERT( ctorCopy.get() == thePointer );

    // Test Assignment
    Pointer<TestClassA> copy = pointer;
    CPPUNIT_ASSERT( copy.get() == thePointer );

    CPPUNIT_ASSERT( ( *pointer ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer->returnHello() == "Hello" );

    copy.reset( NULL );
    CPPUNIT_ASSERT( copy.get() == NULL );

    Pointer<X> p( new X );
    p->next = Pointer<X>( new X );
    p = p->next;
    CPPUNIT_ASSERT( !p->next );
}

////////////////////////////////////////////////////////////////////////////////
template<typename T>
void ConstReferenceMethod( const Pointer<T>& pointer ) {

    Pointer<T> copy = pointer;
    CPPUNIT_ASSERT( copy.get() != NULL );
}

////////////////////////////////////////////////////////////////////////////////
template<typename T>
void ReferenceMethod( Pointer<T>& pointer ) {

    pointer.reset( NULL );
    CPPUNIT_ASSERT( pointer.get() == NULL );
}

////////////////////////////////////////////////////////////////////////////////
Pointer<TestClassA> ReturnByValue() {

    Pointer<TestClassA> pointer( new TestClassA );
    CPPUNIT_ASSERT( pointer.get() != NULL );
    return pointer;
}

////////////////////////////////////////////////////////////////////////////////
const Pointer<TestClassA>& ReturnByConstReference() {

    static Pointer<TestClassA> pointer( new TestClassA );
    CPPUNIT_ASSERT( pointer.get() != NULL );
    return pointer;
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testAssignment() {

    TestClassA* thePointerA = new TestClassA();
    TestClassB* thePointerB = new TestClassB();

    Pointer<TestClassBase> pointer;
    CPPUNIT_ASSERT( pointer.get() == NULL );

    pointer.reset( thePointerA );
    CPPUNIT_ASSERT( pointer.get() == thePointerA );

    pointer.reset( thePointerB );
    CPPUNIT_ASSERT( pointer.get() == thePointerB );

    // Doing this however won't compile.
    //    SomeOtherClass other;
    //    pointer.reset( &other );

    Pointer<TestClassA> pointer1( new TestClassA() );
    Pointer<TestClassA> pointer2 = pointer1;
    Pointer<TestClassA> pointer3 = pointer2;

    CPPUNIT_ASSERT( pointer1.get() == pointer2.get() );
    CPPUNIT_ASSERT( pointer2.get() == pointer3.get() );

    pointer3.reset( NULL );
    CPPUNIT_ASSERT( pointer1.get() != NULL );
    CPPUNIT_ASSERT( pointer2.get() != NULL );
    CPPUNIT_ASSERT( pointer3.get() == NULL );

    ConstReferenceMethod( pointer1 );
    ReferenceMethod( pointer2 );
    CPPUNIT_ASSERT( pointer2.get() == NULL );

    ReturnByValue();

    {
        Pointer<TestClassA> copy = ReturnByValue();
    }

    {
        Pointer<TestClassA> copy = ReturnByConstReference();
    }

    ReturnByConstReference();
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testComparisons() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );

    TestClassA* raw1 = new TestClassA;

    CPPUNIT_ASSERT( ( pointer1 == pointer2 ) == false );
    CPPUNIT_ASSERT( ( pointer1 != pointer2 ) == true );

    CPPUNIT_ASSERT( ( pointer1 == raw1 ) == false );
    CPPUNIT_ASSERT( ( pointer1 != raw1 ) == true );
    CPPUNIT_ASSERT( ( raw1 == pointer2 ) == false );
    CPPUNIT_ASSERT( ( raw1 != pointer2 ) == true );

    delete raw1;

    Pointer<TestClassBase> pointer3( new TestClassA );
    Pointer<TestClassA> pointer4( new TestClassA );

    CPPUNIT_ASSERT( ( pointer3 == pointer4 ) == false );
    CPPUNIT_ASSERT( ( pointer3 != pointer4 ) == true );

    CPPUNIT_ASSERT( pointer1 != NULL );
    CPPUNIT_ASSERT( !pointer1 == false );
    CPPUNIT_ASSERT( !!pointer1 == true );

    // This won't compile which is correct.
    //Pointer<TestClassB> pointer5( new TestClassB );
    //Pointer<TestClassA> pointer6( new TestClassA );
    //CPPUNIT_ASSERT( pointer5 != pointer6 );
}

////////////////////////////////////////////////////////////////////////////////
class PointerTestRunnable : public decaf::lang::Runnable {
private:

    Pointer<TestClassA> mine;

public:

    PointerTestRunnable( const Pointer<TestClassA>& value ) : mine( value ) {}

    void run() {

        for( int i = 0; i < 999; ++i ) {
            Pointer<TestClassBase> copy = this->mine;
            CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
            copy.reset( new TestClassB() );
            CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
        }
    }
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testThreaded1() {
    Pointer<TestClassA> pointer( new TestClassA() );

    PointerTestRunnable runnable( pointer );
    Thread testThread( &runnable );

    testThread.start();

    for( int i = 0; i < 999; ++i ) {
        Pointer<TestClassBase> copy = pointer;
        CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
        Thread::yield();
        copy.reset( new TestClassB() );
        CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
    }

    testThread.join();
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testThreaded2() {
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testOperators() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );
    Pointer<TestClassBase> pointer3;

    CPPUNIT_ASSERT( pointer1->returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer2->returnHello() == "GoodBye" );

    CPPUNIT_ASSERT( ( *pointer1 ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( ( *pointer2 ).returnHello() == "GoodBye" );

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator* on a NULL Should Throw a NullPointerException",
        ( *pointer3 ).returnHello(),
        decaf::lang::exceptions::NullPointerException );
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator-> on a NULL Should Throw a NullPointerException",
        pointer3->returnHello(),
        decaf::lang::exceptions::NullPointerException );

    pointer2.reset( NULL );

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator* on a NULL Should Throw a NullPointerException",
        ( *pointer2 ).returnHello(),
        decaf::lang::exceptions::NullPointerException );
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator-> on a NULL Should Throw a NullPointerException",
        pointer2->returnHello(),
        decaf::lang::exceptions::NullPointerException );
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testSTLContainers() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );
    Pointer<TestClassBase> pointer3( pointer2 );

    CPPUNIT_ASSERT( pointer1.get() != NULL );
    CPPUNIT_ASSERT( pointer2.get() != NULL );

    std::map< Pointer<TestClassBase>, std::string > testMap;

    testMap.insert( std::make_pair( pointer1, "Bob" ) );
    testMap.insert( std::make_pair( pointer2, "Steve" ) );
    testMap.insert( std::make_pair( pointer3, "Steve" ) );

    // Two and Three should be equivalent (not equal) but in this case
    // equivalent is what matters.  So pointer2 should be bumped out of the map.
    CPPUNIT_ASSERT( testMap.size() == 2 );

    testMap.insert( std::make_pair( Pointer<TestClassBase>( new TestClassA ), "Fred" ) );

    CPPUNIT_ASSERT( testMap.find( pointer1 ) != testMap.end() );
    CPPUNIT_ASSERT( testMap.find( pointer2 ) != testMap.end() );

    Pointer< int > one( new int );
    Pointer< int > two( new int );
    Pointer< int > three( new int );

    *one = 1;
    *two = 2;
    *three = 3;

    std::map< Pointer<int>, int, PointerComparator<int> > testMap2;

    CPPUNIT_ASSERT( testMap2.size() == 0 );
    testMap2.insert( std::make_pair( three, 3 ) );
    testMap2.insert( std::make_pair( two, 2 ) );
    testMap2.insert( std::make_pair( one, 1 ) );
    CPPUNIT_ASSERT( testMap2.size() == 3 );

    CPPUNIT_ASSERT( *( testMap2.begin()->first ) == 1 );
    CPPUNIT_ASSERT( *( testMap2.rbegin()->first ) == 3 );
}

////////////////////////////////////////////////////////////////////////////////
class SelfCounting {
private:

    int refCount;

public:

    SelfCounting() : refCount( 0 ) {}
    SelfCounting( const SelfCounting& other ) : refCount( other.refCount ) {}

    void addReference() { this->refCount++; }
    bool releaseReference() { return !( --this->refCount ); }

    std::string returnHello() { return "Hello"; }
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testInvasive() {

    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > thePointer( new SelfCounting );

    // Test Null Initialize
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > nullPointer;
    CPPUNIT_ASSERT( nullPointer.get() == NULL );

    // Test Value Constructor
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > pointer( thePointer );
    CPPUNIT_ASSERT( pointer.get() == thePointer );

    // Test Copy Constructor
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > ctorCopy( pointer );
    CPPUNIT_ASSERT( ctorCopy.get() == thePointer );

    // Test Assignment
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > copy = pointer;
    CPPUNIT_ASSERT( copy.get() == thePointer );

    CPPUNIT_ASSERT( ( *pointer ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer->returnHello() == "Hello" );

    copy.reset( NULL );
    CPPUNIT_ASSERT( copy.get() == NULL );
}
<commit_msg>Add more tests<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "PointerTest.h"

#include <decaf/lang/Pointer.h>
#include <decaf/lang/Thread.h>
#include <decaf/lang/Runnable.h>

#include <map>
#include <string>

using namespace std;
using namespace decaf;
using namespace decaf::lang;

////////////////////////////////////////////////////////////////////////////////
class TestClassBase {
public:

    virtual ~TestClassBase(){}

    virtual std::string returnHello() = 0;

};

////////////////////////////////////////////////////////////////////////////////
class TestClassA : public TestClassBase {
public:

    virtual ~TestClassA() {
        //std::cout << std::endl << "TestClassA - Destructor" << std::endl;
    }

    std::string returnHello() {
        return "Hello";
    }

};

////////////////////////////////////////////////////////////////////////////////
class TestClassB : public TestClassBase {
public:

    virtual ~TestClassB() {
        //std::cout << std::endl << "TestClassB - Destructor" << std::endl;
    }

    std::string returnHello() {
        return "GoodBye";
    }

};

////////////////////////////////////////////////////////////////////////////////
class SomeOtherClass {
public:

};

////////////////////////////////////////////////////////////////////////////////
class ExceptionThrowingClass {
public:

    ExceptionThrowingClass() {
        throw std::bad_alloc();
    }
};

////////////////////////////////////////////////////////////////////////////////
struct X {
    Pointer<X> next;
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testBasics() {

    TestClassA* thePointer = new TestClassA();

    // Test Null Initialize
    Pointer<TestClassA> nullPointer;
    CPPUNIT_ASSERT( nullPointer.get() == NULL );

    // Test Value Constructor
    Pointer<TestClassA> pointer( thePointer );
    CPPUNIT_ASSERT( pointer.get() == thePointer );

    // Test Copy Constructor
    Pointer<TestClassA> ctorCopy( pointer );
    CPPUNIT_ASSERT( ctorCopy.get() == thePointer );

    // Test Assignment
    Pointer<TestClassA> copy = pointer;
    CPPUNIT_ASSERT( copy.get() == thePointer );

    CPPUNIT_ASSERT( ( *pointer ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer->returnHello() == "Hello" );

    copy.reset( NULL );
    CPPUNIT_ASSERT( copy.get() == NULL );

    Pointer<X> p( new X );
    p->next = Pointer<X>( new X );
    p = p->next;
    CPPUNIT_ASSERT( !p->next );

    try{
        Pointer<ExceptionThrowingClass> ex( new ExceptionThrowingClass() );
        CPPUNIT_FAIL( "Should Have Thrown." );
    } catch(...) {}
}

////////////////////////////////////////////////////////////////////////////////
template<typename T>
void ConstReferenceMethod( const Pointer<T>& pointer ) {

    Pointer<T> copy = pointer;
    CPPUNIT_ASSERT( copy.get() != NULL );
}

////////////////////////////////////////////////////////////////////////////////
template<typename T>
void ReferenceMethod( Pointer<T>& pointer ) {

    pointer.reset( NULL );
    CPPUNIT_ASSERT( pointer.get() == NULL );
}

////////////////////////////////////////////////////////////////////////////////
Pointer<TestClassA> ReturnByValue() {

    Pointer<TestClassA> pointer( new TestClassA );
    CPPUNIT_ASSERT( pointer.get() != NULL );
    return pointer;
}

////////////////////////////////////////////////////////////////////////////////
const Pointer<TestClassA>& ReturnByConstReference() {

    static Pointer<TestClassA> pointer( new TestClassA );
    CPPUNIT_ASSERT( pointer.get() != NULL );
    return pointer;
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testAssignment() {

    TestClassA* thePointerA = new TestClassA();
    TestClassB* thePointerB = new TestClassB();

    Pointer<TestClassBase> pointer;
    CPPUNIT_ASSERT( pointer.get() == NULL );

    pointer.reset( thePointerA );
    CPPUNIT_ASSERT( pointer.get() == thePointerA );

    pointer.reset( thePointerB );
    CPPUNIT_ASSERT( pointer.get() == thePointerB );

    // Doing this however won't compile.
    //    SomeOtherClass other;
    //    pointer.reset( &other );

    Pointer<TestClassA> pointer1( new TestClassA() );
    Pointer<TestClassA> pointer2 = pointer1;
    Pointer<TestClassA> pointer3 = pointer2;

    CPPUNIT_ASSERT( pointer1.get() == pointer2.get() );
    CPPUNIT_ASSERT( pointer2.get() == pointer3.get() );

    pointer3.reset( NULL );
    CPPUNIT_ASSERT( pointer1.get() != NULL );
    CPPUNIT_ASSERT( pointer2.get() != NULL );
    CPPUNIT_ASSERT( pointer3.get() == NULL );

    ConstReferenceMethod( pointer1 );
    ReferenceMethod( pointer2 );
    CPPUNIT_ASSERT( pointer2.get() == NULL );

    ReturnByValue();

    {
        Pointer<TestClassA> copy = ReturnByValue();
    }

    {
        Pointer<TestClassA> copy = ReturnByConstReference();
    }

    ReturnByConstReference();
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testComparisons() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );

    TestClassA* raw1 = new TestClassA;

    CPPUNIT_ASSERT( ( pointer1 == pointer2 ) == false );
    CPPUNIT_ASSERT( ( pointer1 != pointer2 ) == true );

    CPPUNIT_ASSERT( ( pointer1 == raw1 ) == false );
    CPPUNIT_ASSERT( ( pointer1 != raw1 ) == true );
    CPPUNIT_ASSERT( ( raw1 == pointer2 ) == false );
    CPPUNIT_ASSERT( ( raw1 != pointer2 ) == true );

    delete raw1;

    Pointer<TestClassBase> pointer3( new TestClassA );
    Pointer<TestClassA> pointer4( new TestClassA );

    CPPUNIT_ASSERT( ( pointer3 == pointer4 ) == false );
    CPPUNIT_ASSERT( ( pointer3 != pointer4 ) == true );

    CPPUNIT_ASSERT( pointer1 != NULL );
    CPPUNIT_ASSERT( !pointer1 == false );
    CPPUNIT_ASSERT( !!pointer1 == true );

    // This won't compile which is correct.
    //Pointer<TestClassB> pointer5( new TestClassB );
    //Pointer<TestClassA> pointer6( new TestClassA );
    //CPPUNIT_ASSERT( pointer5 != pointer6 );
}

////////////////////////////////////////////////////////////////////////////////
class PointerTestRunnable : public decaf::lang::Runnable {
private:

    Pointer<TestClassA> mine;

public:

    PointerTestRunnable( const Pointer<TestClassA>& value ) : mine( value ) {}

    void run() {

        for( int i = 0; i < 999; ++i ) {
            Pointer<TestClassBase> copy = this->mine;
            CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
            copy.reset( new TestClassB() );
            CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
        }
    }
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testThreaded1() {
    Pointer<TestClassA> pointer( new TestClassA() );

    PointerTestRunnable runnable( pointer );
    Thread testThread( &runnable );

    testThread.start();

    for( int i = 0; i < 999; ++i ) {
        Pointer<TestClassBase> copy = pointer;
        CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
        Thread::yield();
        copy.reset( new TestClassB() );
        CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
    }

    testThread.join();
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testThreaded2() {
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testOperators() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );
    Pointer<TestClassBase> pointer3;

    CPPUNIT_ASSERT( pointer1->returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer2->returnHello() == "GoodBye" );

    CPPUNIT_ASSERT( ( *pointer1 ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( ( *pointer2 ).returnHello() == "GoodBye" );

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator* on a NULL Should Throw a NullPointerException",
        ( *pointer3 ).returnHello(),
        decaf::lang::exceptions::NullPointerException );
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator-> on a NULL Should Throw a NullPointerException",
        pointer3->returnHello(),
        decaf::lang::exceptions::NullPointerException );

    pointer2.reset( NULL );

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator* on a NULL Should Throw a NullPointerException",
        ( *pointer2 ).returnHello(),
        decaf::lang::exceptions::NullPointerException );
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "operator-> on a NULL Should Throw a NullPointerException",
        pointer2->returnHello(),
        decaf::lang::exceptions::NullPointerException );
}

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testSTLContainers() {

    Pointer<TestClassBase> pointer1( new TestClassA );
    Pointer<TestClassBase> pointer2( new TestClassB );
    Pointer<TestClassBase> pointer3( pointer2 );

    CPPUNIT_ASSERT( pointer1.get() != NULL );
    CPPUNIT_ASSERT( pointer2.get() != NULL );

    std::map< Pointer<TestClassBase>, std::string > testMap;

    testMap.insert( std::make_pair( pointer1, "Bob" ) );
    testMap.insert( std::make_pair( pointer2, "Steve" ) );
    testMap.insert( std::make_pair( pointer3, "Steve" ) );

    // Two and Three should be equivalent (not equal) but in this case
    // equivalent is what matters.  So pointer2 should be bumped out of the map.
    CPPUNIT_ASSERT( testMap.size() == 2 );

    testMap.insert( std::make_pair( Pointer<TestClassBase>( new TestClassA ), "Fred" ) );

    CPPUNIT_ASSERT( testMap.find( pointer1 ) != testMap.end() );
    CPPUNIT_ASSERT( testMap.find( pointer2 ) != testMap.end() );

    Pointer< int > one( new int );
    Pointer< int > two( new int );
    Pointer< int > three( new int );

    *one = 1;
    *two = 2;
    *three = 3;

    std::map< Pointer<int>, int, PointerComparator<int> > testMap2;

    CPPUNIT_ASSERT( testMap2.size() == 0 );
    testMap2.insert( std::make_pair( three, 3 ) );
    testMap2.insert( std::make_pair( two, 2 ) );
    testMap2.insert( std::make_pair( one, 1 ) );
    CPPUNIT_ASSERT( testMap2.size() == 3 );

    CPPUNIT_ASSERT( *( testMap2.begin()->first ) == 1 );
    CPPUNIT_ASSERT( *( testMap2.rbegin()->first ) == 3 );
}

////////////////////////////////////////////////////////////////////////////////
class SelfCounting {
private:

    int refCount;

public:

    SelfCounting() : refCount( 0 ) {}
    SelfCounting( const SelfCounting& other ) : refCount( other.refCount ) {}

    void addReference() { this->refCount++; }
    bool releaseReference() { return !( --this->refCount ); }

    std::string returnHello() { return "Hello"; }
};

////////////////////////////////////////////////////////////////////////////////
void PointerTest::testInvasive() {

    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > thePointer( new SelfCounting );

    // Test Null Initialize
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > nullPointer;
    CPPUNIT_ASSERT( nullPointer.get() == NULL );

    // Test Value Constructor
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > pointer( thePointer );
    CPPUNIT_ASSERT( pointer.get() == thePointer );

    // Test Copy Constructor
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > ctorCopy( pointer );
    CPPUNIT_ASSERT( ctorCopy.get() == thePointer );

    // Test Assignment
    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > copy = pointer;
    CPPUNIT_ASSERT( copy.get() == thePointer );

    CPPUNIT_ASSERT( ( *pointer ).returnHello() == "Hello" );
    CPPUNIT_ASSERT( pointer->returnHello() == "Hello" );

    copy.reset( NULL );
    CPPUNIT_ASSERT( copy.get() == NULL );
}
<|endoftext|>


<commit_before>/*  Sirikata Network Utilities
 *  ASIOReadBuffer.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  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 Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "util/Platform.hpp"
#include "network/Asio.hpp"
#include "TCPStream.hpp"
#include "util/ThreadSafeQueue.hpp"
#include "ASIOSocketWrapper.hpp"
#include "MultiplexedSocket.hpp"
#include "ASIOReadBuffer.hpp"
namespace Sirikata { namespace Network {
ASIOReadBuffer* MakeASIOReadBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket,unsigned int whichSocket) {
    return parentSocket->getASIOSocketWrapper(whichSocket).setReadBuffer(new ASIOReadBuffer(parentSocket,whichSocket));
}
void ASIOReadBuffer::processError(MultiplexedSocket*parentSocket, const boost::system::error_code &error){
    parentSocket->hostDisconnectedCallback(mWhichBuffer,error);
    parentSocket->getASIOSocketWrapper(mWhichBuffer).clearReadBuffer();
    delete this;
}
bool ASIOReadBuffer::processFullChunk(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket, unsigned int whichSocket, const Stream::StreamID&id, Chunk&newChunk){
    return parentSocket->receiveFullChunk(whichSocket,id,newChunk);
}

void ASIOReadBuffer::readIntoFixedBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket){
    mReadStatus=READING_FIXED_BUFFER;

    parentSocket
        ->getASIOSocketWrapper(mWhichBuffer).getSocket()
        .async_receive(boost::asio::buffer(mBuffer+mBufferPos,sBufferLength-mBufferPos),
                       std::tr1::bind(&ASIOReadBuffer::asioReadIntoFixedBuffer,
                                   this,
                                   _1,
                                   _2));
}
void ASIOReadBuffer::ioReactorThreadResumeRead(std::tr1::shared_ptr<MultiplexedSocket>&thus) {
    assertThreadGroup(*static_cast<const ThreadIdCheck*>(&*thus));
    switch(mReadStatus) {
      case PAUSED_FIXED_BUFFER:
        translateBuffer(thus);
        break;
      case PAUSED_NEW_CHUNK:
        if (processFullChunk(thus,mWhichBuffer,mNewChunkID,mNewChunk)) {
            mNewChunk.resize(0);
            mBufferPos=0;
            readIntoFixedBuffer(thus);
        }
        break;
      case READING_FIXED_BUFFER:
      case READING_NEW_CHUNK:
        break;
    }
}
void ASIOReadBuffer::readIntoChunk(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket){

    mReadStatus=READING_NEW_CHUNK;
    assert(mNewChunk.size()>0);//otherwise should have been filtered out by caller
    assert(mBufferPos<mNewChunk.size());
    parentSocket
        ->getASIOSocketWrapper(mWhichBuffer).getSocket()
        .async_receive(boost::asio::buffer(&*(mNewChunk.begin()+mBufferPos),mNewChunk.size()-mBufferPos),
                       std::tr1::bind(&ASIOReadBuffer::asioReadIntoChunk,
                                   this,
                                   _1,
                                   _2));
}

Stream::StreamID ASIOReadBuffer::processPartialChunk(uint8* dataBuffer, uint32 packetLength, uint32 &bufferReceived, Chunk&retval) {
    unsigned int headerLength=bufferReceived;
    Stream::StreamID retid;
    retid.unserialize(dataBuffer,headerLength);
    assert(headerLength<=bufferReceived&&"High water mark must be greater than maximum StreamID size");
    bufferReceived-=headerLength;
    assert(headerLength<=packetLength&&"High water mark must be greater than maximum StreamID size");
    retval.resize(packetLength-headerLength);
    if (packetLength>headerLength) {
        std::memcpy(&*retval.begin(),dataBuffer+headerLength,bufferReceived);
    }
    return retid;
}
void ASIOReadBuffer::translateBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &thus) {
        unsigned int chunkPos=0;
        unsigned int packetHeaderLength;
        vuint32 packetLength;
        bool readBufferFull=false;
        while ((packetHeaderLength=mBufferPos-chunkPos)!=0&&packetLength.unserialize(mBuffer+chunkPos,packetHeaderLength)) {
            if (mBufferPos-chunkPos<packetLength.read()+packetHeaderLength) {
                if (mBufferPos-chunkPos<sLowWaterMark) {
                    break;//go directly to memmov code and move remnants to beginning of buffer to read a large portion at a time
                }else {
                    mBufferPos-=chunkPos;
                    mBufferPos-=packetHeaderLength;
                    assert(mNewChunk.size()==0);
                    mNewChunkID = processPartialChunk(mBuffer+chunkPos+packetHeaderLength,packetLength.read(),mBufferPos,mNewChunk);
                    readIntoChunk(thus);
                    return;
                }
            }else {
                uint32 chunkLength=packetLength.read();
                Chunk resultChunk;
                Stream::StreamID resultID=processPartialChunk(mBuffer+chunkPos+packetHeaderLength,packetLength.read(),chunkLength,resultChunk);
                if (processFullChunk(thus,mWhichBuffer,resultID,resultChunk)) {
                    chunkPos+=packetHeaderLength+packetLength.read();
                }else {
                    mReadStatus=PAUSED_FIXED_BUFFER;
                    readBufferFull=true;
                    break;//FIXME
                }
            }
        }
        if (chunkPos!=0&&mBufferPos!=chunkPos) {//move partial bytes to beginning
            std::memmove(mBuffer,mBuffer+chunkPos,mBufferPos-chunkPos);
        }
        mBufferPos-=chunkPos;
        if (!readBufferFull) {
            readIntoFixedBuffer(thus);
        }
}
ASIOReadBuffer::~ASIOReadBuffer() {
}

void ASIOReadBuffer::asioReadIntoChunk(const ErrorCode&error,std::size_t bytes_read){
    TCPSSTLOG(this,"rcv",&mNewChunk[mBufferPos],bytes_read,error);
    mBufferPos+=bytes_read;
    std::tr1::shared_ptr<MultiplexedSocket> thus(mParentSocket.lock());

    if (thus) {
        if (error){
            processError(&*thus,error);
        }else {
            if (mBufferPos>=mNewChunk.size()){
                assert(mBufferPos==mNewChunk.size());
                if (processFullChunk(thus,mWhichBuffer,mNewChunkID,mNewChunk)) {
                    mNewChunk.resize(0);
                    mBufferPos=0;
                    readIntoFixedBuffer(thus);
                }else{
                    mReadStatus=PAUSED_NEW_CHUNK;
                }
            }else {
                readIntoChunk(thus);
            }
        }
    }else {
        delete this;
    }
}

void ASIOReadBuffer::asioReadIntoFixedBuffer(const ErrorCode&error,std::size_t bytes_read){
    TCPSSTLOG(this,"rcv",&mBuffer[mBufferPos],bytes_read,error);
    mBufferPos+=bytes_read;
    std::tr1::shared_ptr<MultiplexedSocket> thus(mParentSocket.lock());

    if (thus) {
        if (error){
            processError(&*thus,error);
        }else {
            translateBuffer(thus);
        }
    }else {
        delete this;// the socket is deleted
    }
}
ASIOReadBuffer::ASIOReadBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket,unsigned int whichSocket):mParentSocket(parentSocket){
    mReadStatus=READING_FIXED_BUFFER;
    mBufferPos=0;
    mWhichBuffer=whichSocket;
    readIntoFixedBuffer(parentSocket);
}

} }
<commit_msg>Added some helpful checks to make sure the user does not munge their data when they go about pausing a stream<commit_after>/*  Sirikata Network Utilities
 *  ASIOReadBuffer.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  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 Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "util/Platform.hpp"
#include "network/Asio.hpp"
#include "TCPStream.hpp"
#include "util/ThreadSafeQueue.hpp"
#include "ASIOSocketWrapper.hpp"
#include "MultiplexedSocket.hpp"
#include "ASIOReadBuffer.hpp"
namespace Sirikata { namespace Network {
ASIOReadBuffer* MakeASIOReadBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket,unsigned int whichSocket) {
    return parentSocket->getASIOSocketWrapper(whichSocket).setReadBuffer(new ASIOReadBuffer(parentSocket,whichSocket));
}
void ASIOReadBuffer::processError(MultiplexedSocket*parentSocket, const boost::system::error_code &error){
    parentSocket->hostDisconnectedCallback(mWhichBuffer,error);
    parentSocket->getASIOSocketWrapper(mWhichBuffer).clearReadBuffer();
    delete this;
}
bool ASIOReadBuffer::processFullChunk(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket, unsigned int whichSocket, const Stream::StreamID&id, Chunk&newChunk){
    return parentSocket->receiveFullChunk(whichSocket,id,newChunk);
}

void ASIOReadBuffer::readIntoFixedBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket){
    mReadStatus=READING_FIXED_BUFFER;

    parentSocket
        ->getASIOSocketWrapper(mWhichBuffer).getSocket()
        .async_receive(boost::asio::buffer(mBuffer+mBufferPos,sBufferLength-mBufferPos),
                       std::tr1::bind(&ASIOReadBuffer::asioReadIntoFixedBuffer,
                                   this,
                                   _1,
                                   _2));
}
void ASIOReadBuffer::ioReactorThreadResumeRead(std::tr1::shared_ptr<MultiplexedSocket>&thus) {
    assertThreadGroup(*static_cast<const ThreadIdCheck*>(&*thus));
    switch(mReadStatus) {
      case PAUSED_FIXED_BUFFER:
        translateBuffer(thus);
        break;
      case PAUSED_NEW_CHUNK:
        if (processFullChunk(thus,mWhichBuffer,mNewChunkID,mNewChunk)) {
            mNewChunk.resize(0);
            mBufferPos=0;
            readIntoFixedBuffer(thus);
        }
        break;
      case READING_FIXED_BUFFER:
      case READING_NEW_CHUNK:
        break;
    }
}
void ASIOReadBuffer::readIntoChunk(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket){

    mReadStatus=READING_NEW_CHUNK;
    assert(mNewChunk.size()>0);//otherwise should have been filtered out by caller
    assert(mBufferPos<mNewChunk.size());
    parentSocket
        ->getASIOSocketWrapper(mWhichBuffer).getSocket()
        .async_receive(boost::asio::buffer(&*(mNewChunk.begin()+mBufferPos),mNewChunk.size()-mBufferPos),
                       std::tr1::bind(&ASIOReadBuffer::asioReadIntoChunk,
                                   this,
                                   _1,
                                   _2));
}

Stream::StreamID ASIOReadBuffer::processPartialChunk(uint8* dataBuffer, uint32 packetLength, uint32 &bufferReceived, Chunk&retval) {
    unsigned int headerLength=bufferReceived;
    Stream::StreamID retid;
    retid.unserialize(dataBuffer,headerLength);
    assert(headerLength<=bufferReceived&&"High water mark must be greater than maximum StreamID size");
    bufferReceived-=headerLength;
    assert(headerLength<=packetLength&&"High water mark must be greater than maximum StreamID size");
    retval.resize(packetLength-headerLength);
    if (packetLength>headerLength) {
        std::memcpy(&*retval.begin(),dataBuffer+headerLength,bufferReceived);
    }
    return retid;
}
void ASIOReadBuffer::translateBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &thus) {
        unsigned int chunkPos=0;
        unsigned int packetHeaderLength;
        vuint32 packetLength;
        bool readBufferFull=false;
        while ((packetHeaderLength=mBufferPos-chunkPos)!=0&&packetLength.unserialize(mBuffer+chunkPos,packetHeaderLength)) {
            if (mBufferPos-chunkPos<packetLength.read()+packetHeaderLength) {
                if (mBufferPos-chunkPos<sLowWaterMark) {
                    break;//go directly to memmov code and move remnants to beginning of buffer to read a large portion at a time
                }else {
                    mBufferPos-=chunkPos;
                    mBufferPos-=packetHeaderLength;
                    assert(mNewChunk.size()==0);
                    mNewChunkID = processPartialChunk(mBuffer+chunkPos+packetHeaderLength,packetLength.read(),mBufferPos,mNewChunk);
                    readIntoChunk(thus);
                    return;
                }
            }else {
                uint32 chunkLength=packetLength.read();
                Chunk resultChunk;
                Stream::StreamID resultID=processPartialChunk(mBuffer+chunkPos+packetHeaderLength,packetLength.read(),chunkLength,resultChunk);
                size_t vectorSize=resultChunk.size();
                if (processFullChunk(thus,mWhichBuffer,resultID,resultChunk)) {
                    chunkPos+=packetHeaderLength+packetLength.read();
                }else {
                    assert(resultChunk.size()==vectorSize);//if the user rejects the packet they should not munge it
                    mReadStatus=PAUSED_FIXED_BUFFER;
                    readBufferFull=true;
                    break;//FIXME
                }
            }
        }
        if (chunkPos!=0&&mBufferPos!=chunkPos) {//move partial bytes to beginning
            std::memmove(mBuffer,mBuffer+chunkPos,mBufferPos-chunkPos);
        }
        mBufferPos-=chunkPos;
        if (!readBufferFull) {
            readIntoFixedBuffer(thus);
        }
}
ASIOReadBuffer::~ASIOReadBuffer() {
}

void ASIOReadBuffer::asioReadIntoChunk(const ErrorCode&error,std::size_t bytes_read){
    TCPSSTLOG(this,"rcv",&mNewChunk[mBufferPos],bytes_read,error);
    mBufferPos+=bytes_read;
    std::tr1::shared_ptr<MultiplexedSocket> thus(mParentSocket.lock());

    if (thus) {
        if (error){
            processError(&*thus,error);
        }else {
            if (mBufferPos>=mNewChunk.size()){
                size_t vectorSize=mNewChunk.size();
                assert(mBufferPos==vectorSize);
                if (processFullChunk(thus,mWhichBuffer,mNewChunkID,mNewChunk)) {
                    mNewChunk.resize(0);
                    mBufferPos=0;
                    readIntoFixedBuffer(thus);
                }else{
                    assert(mNewChunk.size()==vectorSize);//if the user rejects the packet they should not munge it. This is a high level check of that
                    mReadStatus=PAUSED_NEW_CHUNK;
                }
            }else {
                readIntoChunk(thus);
            }
        }
    }else {
        delete this;
    }
}

void ASIOReadBuffer::asioReadIntoFixedBuffer(const ErrorCode&error,std::size_t bytes_read){
    TCPSSTLOG(this,"rcv",&mBuffer[mBufferPos],bytes_read,error);
    mBufferPos+=bytes_read;
    std::tr1::shared_ptr<MultiplexedSocket> thus(mParentSocket.lock());

    if (thus) {
        if (error){
            processError(&*thus,error);
        }else {
            translateBuffer(thus);
        }
    }else {
        delete this;// the socket is deleted
    }
}
ASIOReadBuffer::ASIOReadBuffer(const std::tr1::shared_ptr<MultiplexedSocket> &parentSocket,unsigned int whichSocket):mParentSocket(parentSocket){
    mReadStatus=READING_FIXED_BUFFER;
    mBufferPos=0;
    mWhichBuffer=whichSocket;
    readIntoFixedBuffer(parentSocket);
}

} }
<|endoftext|>


<commit_before>#include "nanyc-utils.h"

using namespace Yuni;

int main(int argc, const char** argv)
{
	const char* const argv0 = argv[0];

	if (argc > 1)
	{
		nyrun_cf_t runcf;
		nyrun_cf_init(&runcf);

		int firstarg = argc; // end of the list

		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};

						if (arg == "--help")
							return ny::print::usage(argv[0]);
						if (arg == "--version")
							return ny::print::version();
						if (arg == "--bugreport")
							return ny::print::bugReportInfo();
						if (arg == "--verbose")
						{
							runcf.verbose = nytrue;
							continue;
						}
						return ny::print::unknownOption(argv0, arg);
					}
					else
					{
						// nothing must interpreted after '--'
						firstarg = i + 1;
						break;
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return ny::print::usage(argv[0]);
					if (arg == "-v")
						return ny::print::version();
					return ny::print::unknownOption(argv0, arg);
				}
			}
			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		int exitstatus = -1;
		if (firstarg < argc)
		{
			// callbacks
			runcf.build.on_error_file_eacces = &ny::print::fileAccessError;

			// the new arguments, after removing all command line arguments
			int nargc = argc - firstarg;
			const char** nargv = argv + firstarg;
			// the nany sript to load, which should be the first new argument
			const char* nargv0 = nargv[0];

			--nargc;
			uint32_t pargc = (nargc > 0) ? static_cast<uint32_t>(nargc) : 0;
			const char** pargv = (!pargc ? nullptr : (++nargv));

			exitstatus = nyrun_file_n(&runcf, nargv0, strlen(nargv0), pargc, pargv);
		}

		nyrun_cf_release(&runcf);
		return exitstatus;
	}
	return ny::print::noInputScript(argv0);
}
<commit_msg>nanyc: remove temporary variable argv0<commit_after>#include "nanyc-utils.h"

using namespace Yuni;

int main(int argc, const char** argv)
{
	if (argc > 1)
	{
		nyrun_cf_t runcf;
		nyrun_cf_init(&runcf);

		int firstarg = argc; // end of the list

		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};

						if (arg == "--help")
							return ny::print::usage(argv[0]);
						if (arg == "--version")
							return ny::print::version();
						if (arg == "--bugreport")
							return ny::print::bugReportInfo();
						if (arg == "--verbose")
						{
							runcf.verbose = nytrue;
							continue;
						}
						return ny::print::unknownOption(argv[0], arg);
					}
					else
					{
						// nothing must interpreted after '--'
						firstarg = i + 1;
						break;
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return ny::print::usage(argv[0]);
					if (arg == "-v")
						return ny::print::version();
					return ny::print::unknownOption(argv[0], arg);
				}
			}
			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		int exitstatus = -1;
		if (firstarg < argc)
		{
			// callbacks
			runcf.build.on_error_file_eacces = &ny::print::fileAccessError;

			// the new arguments, after removing all command line arguments
			int nargc = argc - firstarg;
			const char** nargv = argv + firstarg;
			// the nany sript to load, which should be the first new argument
			const char* nargv0 = nargv[0];

			--nargc;
			uint32_t pargc = (nargc > 0) ? static_cast<uint32_t>(nargc) : 0;
			const char** pargv = (!pargc ? nullptr : (++nargv));

			exitstatus = nyrun_file_n(&runcf, nargv0, strlen(nargv0), pargc, pargv);
		}

		nyrun_cf_release(&runcf);
		return exitstatus;
	}
	return ny::print::noInputScript(argv[0]);
}
<|endoftext|>


<commit_before>#include "compression.h"

using namespace dariadb;
using namespace dariadb::compression::v2;

CopmressedWriter::CopmressedWriter(const ByteBuffer_Ptr &bw)
	: time_comp(bw), value_comp(bw), flag_comp(bw), _bb(bw) {
	_is_first = true;
	_is_full = false;
}

CopmressedWriter::~CopmressedWriter() {}

bool CopmressedWriter::append(const Meas &m) {
	if (_is_first) {
		_first = m;
		_is_first = false;
	}

	auto t_f = time_comp.append(m.time);
	auto f_f = value_comp.append(m.value);
	auto v_f = flag_comp.append(m.flag);

	if (!t_f || !f_f || !v_f) {
		_is_full = true;
		return false;
	}
	else {
		return true;
	}
}

CopmressedReader::CopmressedReader(const ByteBuffer_Ptr &bw, const Meas &first) : time_dcomp(bw, first.time), value_dcomp(bw, first.value),
flag_dcomp(bw, first.flag) {
	_first = first;
}

CopmressedReader::~CopmressedReader() {}
<commit_msg>build.<commit_after>#include "compression.h"

using namespace dariadb;
using namespace dariadb::compression::v2;

CopmressedWriter::CopmressedWriter(const ByteBuffer_Ptr &bw)
	: _bb(bw), time_comp(bw), value_comp(bw), flag_comp(bw) {
	_is_first = true;
	_is_full = false;
}

CopmressedWriter::~CopmressedWriter() {}

bool CopmressedWriter::append(const Meas &m) {
	if (_is_first) {
		_first = m;
		_is_first = false;
	}

	auto t_f = time_comp.append(m.time);
	auto f_f = value_comp.append(m.value);
	auto v_f = flag_comp.append(m.flag);

	if (!t_f || !f_f || !v_f) {
		_is_full = true;
		return false;
	}
	else {
		return true;
	}
}

CopmressedReader::CopmressedReader(const ByteBuffer_Ptr &bw, const Meas &first) : time_dcomp(bw, first.time), value_dcomp(bw, first.value),
flag_dcomp(bw, first.flag) {
	_first = first;
}

CopmressedReader::~CopmressedReader() {}
<|endoftext|>


<commit_before><commit_msg>account for the changes on point types<commit_after><|endoftext|>


<commit_before>#include "stdsneezy.h"
#include "database.h"
#include "corporation.h"

sstring TCorporation::getName()
{
  TDatabase db(DB_SNEEZY);

  db.query("select name from corporation where corp_id=%i", corp_id);
  db.fetchRow();
  return db["name"];
}

TCorporation::TCorporation(int c) :
  corp_id(c)
{
}

TCorporation::~TCorporation(){
}

void TCorporation::corpLog(const sstring &name, const sstring &action, int talens)
{
  TDatabase db(DB_SNEEZY);

  db.query("insert into corplog values (%i, '%s', '%s', %i, %i, now())",
	   corp_id, name.c_str(), action.c_str(), talens, getMoney());
}

int TCorporation::getAccess(TBeing *ch){
  TDatabase db(DB_SNEEZY);

  db.query("select access from corpaccess where corp_id=%i and lower(name)='%s'", corp_id, sstring(ch->getName()).lower().c_str());

  if(db.fetchRow()){
    return convertTo<int>(db["access"]);
  }

  return 0;
}

bool TCorporation::hasAccess(TBeing *ch, int perm){
  TDatabase db(DB_SNEEZY);
  int access;

  db.query("select access from corpaccess where corp_id=%i and lower(name)='%s'",
	   corp_id, sstring(ch->getName()).lower().c_str());

  if(db.fetchRow()){
    access=convertTo<int>(db["access"]);
  } else {
    access=0;
  }

  return (access & perm);
}

int TCorporation::getBank()
{
  TDatabase db(DB_SNEEZY);

  db.query("select bank from corporation where corp_id=%i", corp_id);

  if(db.fetchRow())
    return convertTo<int>(db["bank"]);
  else
    return 4; // default to GH bank
}

void TCorporation::setBank(int bank)
{
  TDatabase db(DB_SNEEZY);

  db.query("update corporation set bank=%i where corp_id=%i", bank, corp_id);

}

int TCorporation::getMoney()
{
  TDatabase db(DB_SNEEZY);

  db.query("select talens from shopownedcorpbank b, corporation c where c.corp_id=%i and c.corp_id=b.corp_id and b.shop_nr=c.bank", corp_id);

  if(db.fetchRow())
    return convertTo<int>(db["talens"]);
  else
    return 0;
}

void TCorporation::setMoney(int g)
{
  TDatabase db(DB_SNEEZY);

  db.query("update shopownedcorpbank set talens=%i where corp_id=corporation.corp_id and corporation.corp_id=%i and shop_nr=corporation.bank", g, corp_id);
}

int TCorporation::getCorpID()
{
  return corp_id;
}

int TCorporation::getAssets()
{
  int value=0, keepernum=0;
  TDatabase db(DB_SNEEZY);
  TObj *o=NULL;
  TRoom *room;
  TMonster *keeper;

  db.query("select in_room, keeper from shop where shop_nr in (select shop_nr from shopowned where corp_id=%i)", corp_id);

  while(db.fetchRow()){
    room=real_roomp(convertTo<int>(db["in_room"]));
    keepernum=convertTo<int>(db["keeper"]);

    for(TThing *tt=room->getStuff();tt;tt=tt->nextThing){
      if((keeper=dynamic_cast<TMonster *>(tt)) &&
	 keeper->mobVnum() == keepernum){
	for(TThing *t=keeper->getStuff();t;t=t->nextThing){
	  o=dynamic_cast<TObj *>(t);
	  value+=o->obj_flags.cost;
	}
        break;
      }
    }
  }

  return value;
}

vector <corp_list_data> getCorpListingData(void)
{
  TDatabase db(DB_SNEEZY);
  int corp_id=0, val=0, gold=0, shopval=0, bankowner=0, bankgold=0;
  vector <corp_list_data> corp_list;
  corp_list_data corp_list_item;

  db.query("select c.corp_id, c.name, sum(s.gold) as gold, b.talens as bankgold, count(so.shop_nr) as shopcount, sob.corp_id as bankowner from (((corporation c left outer join shopownedcorpbank b on (b.corp_id=c.corp_id and c.bank=b.shop_nr)) left outer join shopowned sob on (sob.shop_nr=c.bank)) left outer join shopowned so on (c.corp_id=so.corp_id)) left outer join shop s on (so.shop_nr=s.shop_nr) group by c.corp_id, c.name, b.talens, sob.corp_id order by sum(s.gold)+b.talens desc");

  while(db.fetchRow()){
    corp_id=convertTo<int>(db["corp_id"]);
    gold=convertTo<int>(db["gold"]);
    bankgold=convertTo<int>(db["bankgold"]);
    shopval=convertTo<int>(db["shopcount"]) * 1000000;
    bankowner=convertTo<int>(db["bankowner"]);

    TCorporation corp(corp_id);

    // if we don't own the bank, record our gold that's in the bank
    // otherwise we end up counting it twice
    if(bankowner!=corp_id)
      gold += bankgold;

    val=gold+corp.getAssets()+shopval;

    corp_list_item.rank=val;
    corp_list_item.corp_id=corp_id;
    corp_list_item.name=db["name"];
    corp_list_item.gold=gold;
    corp_list_item.assets=corp.getAssets()+shopval;
    corp_list.push_back(corp_list_item);
  }

  return corp_list;
}

<commit_msg>added crash prevention check for when a room can't be found<commit_after>#include "stdsneezy.h"
#include "database.h"
#include "corporation.h"

sstring TCorporation::getName()
{
  TDatabase db(DB_SNEEZY);

  db.query("select name from corporation where corp_id=%i", corp_id);
  db.fetchRow();
  return db["name"];
}

TCorporation::TCorporation(int c) :
  corp_id(c)
{
}

TCorporation::~TCorporation(){
}

void TCorporation::corpLog(const sstring &name, const sstring &action, int talens)
{
  TDatabase db(DB_SNEEZY);

  db.query("insert into corplog values (%i, '%s', '%s', %i, %i, now())",
	   corp_id, name.c_str(), action.c_str(), talens, getMoney());
}

int TCorporation::getAccess(TBeing *ch){
  TDatabase db(DB_SNEEZY);

  db.query("select access from corpaccess where corp_id=%i and lower(name)='%s'", corp_id, sstring(ch->getName()).lower().c_str());

  if(db.fetchRow()){
    return convertTo<int>(db["access"]);
  }

  return 0;
}

bool TCorporation::hasAccess(TBeing *ch, int perm){
  TDatabase db(DB_SNEEZY);
  int access;

  db.query("select access from corpaccess where corp_id=%i and lower(name)='%s'",
	   corp_id, sstring(ch->getName()).lower().c_str());

  if(db.fetchRow()){
    access=convertTo<int>(db["access"]);
  } else {
    access=0;
  }

  return (access & perm);
}

int TCorporation::getBank()
{
  TDatabase db(DB_SNEEZY);

  db.query("select bank from corporation where corp_id=%i", corp_id);

  if(db.fetchRow())
    return convertTo<int>(db["bank"]);
  else
    return 4; // default to GH bank
}

void TCorporation::setBank(int bank)
{
  TDatabase db(DB_SNEEZY);

  db.query("update corporation set bank=%i where corp_id=%i", bank, corp_id);

}

int TCorporation::getMoney()
{
  TDatabase db(DB_SNEEZY);

  db.query("select talens from shopownedcorpbank b, corporation c where c.corp_id=%i and c.corp_id=b.corp_id and b.shop_nr=c.bank", corp_id);

  if(db.fetchRow())
    return convertTo<int>(db["talens"]);
  else
    return 0;
}

void TCorporation::setMoney(int g)
{
  TDatabase db(DB_SNEEZY);

  db.query("update shopownedcorpbank set talens=%i where corp_id=corporation.corp_id and corporation.corp_id=%i and shop_nr=corporation.bank", g, corp_id);
}

int TCorporation::getCorpID()
{
  return corp_id;
}

int TCorporation::getAssets()
{
  int value=0, keepernum=0;
  TDatabase db(DB_SNEEZY);
  TObj *o=NULL;
  TRoom *room;
  TMonster *keeper;

  db.query("select in_room, keeper from shop where shop_nr in (select shop_nr from shopowned where corp_id=%i)", corp_id);

  while(db.fetchRow()){
    room=real_roomp(convertTo<int>(db["in_room"]));
    keepernum=convertTo<int>(db["keeper"]);

    if(!room)
      continue;

    for(TThing *tt=room->getStuff();tt;tt=tt->nextThing){
      if((keeper=dynamic_cast<TMonster *>(tt)) &&
	 keeper->mobVnum() == keepernum){
	for(TThing *t=keeper->getStuff();t;t=t->nextThing){
	  o=dynamic_cast<TObj *>(t);
	  value+=o->obj_flags.cost;
	}
        break;
      }
    }
  }

  return value;
}

vector <corp_list_data> getCorpListingData(void)
{
  TDatabase db(DB_SNEEZY);
  int corp_id=0, val=0, gold=0, shopval=0, bankowner=0, bankgold=0;
  vector <corp_list_data> corp_list;
  corp_list_data corp_list_item;

  db.query("select c.corp_id, c.name, sum(s.gold) as gold, b.talens as bankgold, count(so.shop_nr) as shopcount, sob.corp_id as bankowner from (((corporation c left outer join shopownedcorpbank b on (b.corp_id=c.corp_id and c.bank=b.shop_nr)) left outer join shopowned sob on (sob.shop_nr=c.bank)) left outer join shopowned so on (c.corp_id=so.corp_id)) left outer join shop s on (so.shop_nr=s.shop_nr) group by c.corp_id, c.name, b.talens, sob.corp_id order by sum(s.gold)+b.talens desc");

  while(db.fetchRow()){
    corp_id=convertTo<int>(db["corp_id"]);
    gold=convertTo<int>(db["gold"]);
    bankgold=convertTo<int>(db["bankgold"]);
    shopval=convertTo<int>(db["shopcount"]) * 1000000;
    bankowner=convertTo<int>(db["bankowner"]);

    TCorporation corp(corp_id);

    // if we don't own the bank, record our gold that's in the bank
    // otherwise we end up counting it twice
    if(bankowner!=corp_id)
      gold += bankgold;

    val=gold+corp.getAssets()+shopval;

    corp_list_item.rank=val;
    corp_list_item.corp_id=corp_id;
    corp_list_item.name=db["name"];
    corp_list_item.gold=gold;
    corp_list_item.assets=corp.getAssets()+shopval;
    corp_list.push_back(corp_list_item);
  }

  return corp_list;
}

<|endoftext|>


<commit_before><commit_msg>Prediction: move interaction feature into offline mode for training only<commit_after><|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
/*
 * CompositingVisualLoop.cpp
 *
 *  Created on: 16 janv. 2012
 *      Author: Jeremy Ringard
 */

//#define DEBUG_DRAW

#include <sofa/component/visualmodel/CompositingVisualLoop.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/component/visualmodel/VisualStyle.h>
#include <sofa/core/visual/DisplayFlags.h>
#include <sofa/simulation/common/VisualVisitor.h>
#include <sofa/simulation/common/UpdateContextVisitor.h>
#include <sofa/simulation/common/UpdateMappingVisitor.h>
#include <sofa/simulation/common/UpdateMappingEndEvent.h>
#include <sofa/simulation/common/PropagateEventVisitor.h>

#include <sofa/helper/AdvancedTimer.h>

namespace sofa
{
namespace component
{
namespace visualmodel
{

SOFA_DECL_CLASS(CompositingVisualLoop);

int CompositingVisualLoopClass = core::RegisterObject("Visual loop enabling multipass rendering. Needs multiple fbo data and a compositing shader")
        .add< CompositingVisualLoop >()
        ;

CompositingVisualLoop::CompositingVisualLoop(simulation::Node* _gnode)
    : simulation::DefaultVisualManagerLoop(_gnode),
      vertFilename(initData(&vertFilename, (std::string) "shaders/compositing.vert", "vertFilename", "Set the vertex shader filename to load")),
      fragFilename(initData(&fragFilename, (std::string) "shaders/compositing.frag", "fragFilename", "Set the fragment shader filename to load"))
{
    //assert(gRoot);
}

CompositingVisualLoop::~CompositingVisualLoop()
{}

void CompositingVisualLoop::initVisual()
{}

void CompositingVisualLoop::init()
{
    if (!gRoot)
        gRoot = dynamic_cast<simulation::Node*>(this->getContext());
}

//should not be called if scene file is well formed
void CompositingVisualLoop::defaultRendering(sofa::core::visual::VisualParams* vparams)
{
    vparams->pass() = sofa::core::visual::VisualParams::Std;
    VisualDrawVisitor act ( vparams );
    gRoot->execute ( &act );
    vparams->pass() = sofa::core::visual::VisualParams::Transparent;
    VisualDrawVisitor act2 ( vparams );
    gRoot->execute ( &act2 );
}

void CompositingVisualLoop::drawStep(sofa::core::visual::VisualParams* vparams)
{
    if ( !gRoot ) return;

    sofa::core::visual::tristate renderingState;
    //vparams->displayFlags().setShowRendering(false);
    component::visualmodel::VisualStyle::SPtr visualStyle = NULL;
    gRoot->get(visualStyle);
    const sofa::core::visual::DisplayFlags &backupFlags = vparams->displayFlags();
    const sofa::core::visual::DisplayFlags &currentFlags = visualStyle->displayFlags.getValue();
    vparams->displayFlags() = sofa::core::visual::merge_displayFlags(backupFlags, currentFlags);
    renderingState = vparams->displayFlags().getShowRendering();
    if (vparams->displayFlags().getShowRendering())
        //std::cout << "Advanced Rendering is ON" << std::endl;
        else
        {
            //std::cout << "Advanced Rendering is OFF" << std::endl;
            defaultRendering(vparams);
        }

    //should not happen: the compositing loop relies on one or more rendered passes done by the VisualManagerPass component
    if (gRoot->visualManager.empty())
    {
        serr << "CompositingVisualLoop: no VisualManagerPass found. Disable multipass rendering." << sendl;
        defaultRendering(vparams);
    }

    //rendering sequence: call each VisualManagerPass elements, then composite the frames
    else
    {
        if (renderingState == sofa::core::visual::tristate::false_value || renderingState == sofa::core::visual::tristate::neutral_value) return;

        Node::Sequence<core::visual::VisualManager>::iterator begin = gRoot->visualManager.begin(), end = gRoot->visualManager.end(), it;
        VisualManagerPass* currentVMP;
        bool stopLoop=false;
        //preDraw sequence
        it=begin;
        for (it = begin; it != end; ++it)
        {
            (*it)->preDrawScene(vparams);
            currentVMP=dynamic_cast<VisualManagerPass*>(*it);
            if( currentVMP!=NULL && !currentVMP->isPrerendered())
            {
#ifdef DEBUG_DRAW
                std::cout<<"final pass is "<<currentVMP->getName()<< "end of predraw loop" <<std::endl;
#endif
                break;
            }
        }
        //Draw sequence
        bool rendered = false; // true if a manager did the rendering
        for (it = begin; it != end; ++it)
            if ((*it)->drawScene(vparams))	{ rendered = true; 	break;	}

        if (!rendered) // do the rendering
        {
            std::cerr << "VisualLoop error: no visualManager rendered the scene. Please make sure the final visualManager(Secondary)Pass has a renderToScreen=\"true\" attribute" << std::endl;
        }
        //postDraw sequence
        Node::Sequence<core::visual::VisualManager>::reverse_iterator rbegin = gRoot->visualManager.rbegin(), rend = gRoot->visualManager.rend(), rit;
        for (rit = rbegin; rit != rend; ++rit)
            (*rit)->postDrawScene(vparams);
    }
}

} // namespace visualmodel
} // namespace component
} //sofa
<commit_msg>r12115/sofa-dev : FIX: compilation<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
/*
 * CompositingVisualLoop.cpp
 *
 *  Created on: 16 janv. 2012
 *      Author: Jeremy Ringard
 */

//#define DEBUG_DRAW

#include <sofa/component/visualmodel/CompositingVisualLoop.h>
#include <sofa/core/ObjectFactory.h>
#include <sofa/component/visualmodel/VisualStyle.h>
#include <sofa/core/visual/DisplayFlags.h>
#include <sofa/simulation/common/VisualVisitor.h>
#include <sofa/simulation/common/UpdateContextVisitor.h>
#include <sofa/simulation/common/UpdateMappingVisitor.h>
#include <sofa/simulation/common/UpdateMappingEndEvent.h>
#include <sofa/simulation/common/PropagateEventVisitor.h>

#include <sofa/helper/AdvancedTimer.h>

namespace sofa
{
namespace component
{
namespace visualmodel
{

SOFA_DECL_CLASS(CompositingVisualLoop);

int CompositingVisualLoopClass = core::RegisterObject("Visual loop enabling multipass rendering. Needs multiple fbo data and a compositing shader")
        .add< CompositingVisualLoop >()
        ;

CompositingVisualLoop::CompositingVisualLoop(simulation::Node* _gnode)
    : simulation::DefaultVisualManagerLoop(_gnode),
      vertFilename(initData(&vertFilename, (std::string) "shaders/compositing.vert", "vertFilename", "Set the vertex shader filename to load")),
      fragFilename(initData(&fragFilename, (std::string) "shaders/compositing.frag", "fragFilename", "Set the fragment shader filename to load"))
{
    //assert(gRoot);
}

CompositingVisualLoop::~CompositingVisualLoop()
{}

void CompositingVisualLoop::initVisual()
{}

void CompositingVisualLoop::init()
{
    if (!gRoot)
        gRoot = dynamic_cast<simulation::Node*>(this->getContext());
}

//should not be called if scene file is well formed
void CompositingVisualLoop::defaultRendering(sofa::core::visual::VisualParams* vparams)
{
    vparams->pass() = sofa::core::visual::VisualParams::Std;
    VisualDrawVisitor act ( vparams );
    gRoot->execute ( &act );
    vparams->pass() = sofa::core::visual::VisualParams::Transparent;
    VisualDrawVisitor act2 ( vparams );
    gRoot->execute ( &act2 );
}

void CompositingVisualLoop::drawStep(sofa::core::visual::VisualParams* vparams)
{
    if ( !gRoot ) return;

    sofa::core::visual::tristate renderingState;
    //vparams->displayFlags().setShowRendering(false);
    component::visualmodel::VisualStyle::SPtr visualStyle = NULL;
    gRoot->get(visualStyle);
    const sofa::core::visual::DisplayFlags &backupFlags = vparams->displayFlags();
    const sofa::core::visual::DisplayFlags &currentFlags = visualStyle->displayFlags.getValue();
    vparams->displayFlags() = sofa::core::visual::merge_displayFlags(backupFlags, currentFlags);
    renderingState = vparams->displayFlags().getShowRendering();
    if (vparams->displayFlags().getShowRendering())
    {
        //std::cout << "Advanced Rendering is ON" << std::endl;
    }
    else
    {
        //std::cout << "Advanced Rendering is OFF" << std::endl;
        defaultRendering(vparams);
        return;
    }

    //should not happen: the compositing loop relies on one or more rendered passes done by the VisualManagerPass component
    if (gRoot->visualManager.empty())
    {
        serr << "CompositingVisualLoop: no VisualManagerPass found. Disable multipass rendering." << sendl;
        defaultRendering(vparams);
    }

    //rendering sequence: call each VisualManagerPass elements, then composite the frames
    else
    {
        if (renderingState == sofa::core::visual::tristate::false_value || renderingState == sofa::core::visual::tristate::neutral_value) return;

        Node::Sequence<core::visual::VisualManager>::iterator begin = gRoot->visualManager.begin(), end = gRoot->visualManager.end(), it;
        VisualManagerPass* currentVMP;
        bool stopLoop=false;
        //preDraw sequence
        it=begin;
        for (it = begin; it != end; ++it)
        {
            (*it)->preDrawScene(vparams);
            currentVMP=dynamic_cast<VisualManagerPass*>(*it);
            if( currentVMP!=NULL && !currentVMP->isPrerendered())
            {
#ifdef DEBUG_DRAW
                std::cout<<"final pass is "<<currentVMP->getName()<< "end of predraw loop" <<std::endl;
#endif
                break;
            }
        }
        //Draw sequence
        bool rendered = false; // true if a manager did the rendering
        for (it = begin; it != end; ++it)
            if ((*it)->drawScene(vparams))	{ rendered = true; 	break;	}

        if (!rendered) // do the rendering
        {
            std::cerr << "VisualLoop error: no visualManager rendered the scene. Please make sure the final visualManager(Secondary)Pass has a renderToScreen=\"true\" attribute" << std::endl;
        }
        //postDraw sequence
        Node::Sequence<core::visual::VisualManager>::reverse_iterator rbegin = gRoot->visualManager.rbegin(), rend = gRoot->visualManager.rend(), rit;
        for (rit = rbegin; rit != rend; ++rit)
            (*rit)->postDrawScene(vparams);
    }
}

} // namespace visualmodel
} // namespace component
} //sofa
<|endoftext|>