<commit_before>#include <miopen/gcn_asm_utils.h>
#include <miopen/errors.hpp>
#include <cstdlib>
#include <cassert>
#include <fstream>
#include <sstream>
#include <cstdio>
#include  <cctype>

#ifndef _WIN32
#include <ext/stdio_filebuf.h>
#include <unistd.h>
#include <sys/wait.h>
#endif // !WIN32

static std::string CleanupPath(const char * p);
static int ExecuteGcnAssembler(const std::string& p, std::vector<std::string>& args, std::istream* in, std::ostream* out);

#ifndef _WIN32
class Pipe
{
public:
    Pipe()
        : _read_side_closed(true)
        , _write_side_closed(true)
    {
    }

    Pipe(Pipe&&) = delete;
    Pipe(Pipe&) = delete;
    Pipe& operator =(Pipe&) = delete;
    ~Pipe() { Close(); }
    void CloseRead() { CloseSide(_read_side, _read_side_closed); }
    void CloseWrite() { CloseSide(_write_side, _write_side_closed); }
    int DupRead(int target_fd) { assert(!_read_side_closed); return dup2(_read_side, target_fd); }
    int DupWrite(int target_fd) { assert(!_write_side_closed); return dup2(_write_side, target_fd); }
    int GetReadFd() { return _read_side; }
    int GetWriteFd() { return _write_side; }

    void Close()
    {
        CloseRead();
        CloseWrite();
    }

    void Open()
    {
        if (pipe(_sides)) { MIOPEN_THROW("Error: pipe()"); }
        _read_side_closed = false;
        _write_side_closed = false;
    }

private:
    union
    {
        int _sides[2];
        struct
        {
            int _read_side;
            int _write_side;
        };
    };

    bool _read_side_closed;
    bool _write_side_closed;

    static void CloseSide(int fd, bool& closed)
    {
        if (closed) { return; }
        if (close(fd)) { std::fprintf(stderr, "Error closing pipe"); }
        closed = true;
    }
};
#endif // !WIN32

std::string GetGcnAssemblerPath()
{
    const auto asm_path_env_p = std::getenv("MIOPEN_EXPERIMENTAL_GCN_ASM_PATH");
    if (asm_path_env_p) {
        return CleanupPath(asm_path_env_p);
    }
#ifdef MIOPEN_AMDGCN_ASSEMBLER // string literal generated by CMake
    return CleanupPath(MIOPEN_AMDGCN_ASSEMBLER);
#else
    return "";
#endif
}

bool ValidateGcnAssembler()
{
#ifndef _WIN32
    const auto path = GetGcnAssemblerPath();
    if (path.empty()) { return false; }
    if (!std::ifstream(path).good()) { return false; }

    std::vector<std::string> args({"--version"});
    std::stringstream clang_stdout;
    std::string clang_result_line;
    auto clang_rc = ExecuteGcnAssembler(path, args, nullptr, &clang_stdout);

    if (clang_rc != 0) { return false; }

    std::getline(clang_stdout, clang_result_line);
    if (clang_result_line.find("clang") != std::string::npos)

    while (!clang_stdout.eof()) {
        std::getline(clang_stdout, clang_result_line);

        if (clang_result_line.find("Target: ") != std::string::npos) {
            return clang_result_line.find("amdgcn") != std::string::npos;
        }
    }
#endif // !WIN32
    return false;
}

static
int ExecuteGcnAssembler(const std::string& p, std::vector<std::string>& args, std::istream* in, std::ostream* out)
{
#ifndef _WIN32
    Pipe clang_stdin;
    Pipe clang_stdout;

    const auto redirect_stdin = (in != nullptr);
    const auto redirect_stdout = (out != nullptr);

    if (redirect_stdin) { clang_stdin.Open(); }
    if (redirect_stdout) { clang_stdout.Open(); }

    int wstatus;
    pid_t pid = fork();
    if (pid == 0) {
        std::string path(p); // to remove constness
        std::vector<char*> c_args;
        c_args.push_back(&path[0]);
        for (auto& arg : args) {
            c_args.push_back(&arg[0]);
        }
        c_args.push_back(nullptr);

        if (redirect_stdin) {
            if (clang_stdin.DupRead(STDIN_FILENO) == -1) { std::exit(EXIT_FAILURE); }
            clang_stdin.Close();
        }

        if (redirect_stdout) {
            if (clang_stdout.DupWrite(STDOUT_FILENO) == -1) { std::exit(EXIT_FAILURE); }
            clang_stdout.Close();
        }

        clang_stdout.Close();

        execv(path.c_str(), c_args.data());
        std::exit(EXIT_FAILURE);
    }
    else {
        if (pid == -1) { MIOPEN_THROW("Error X-AMDGCN-ASM: fork()"); }

        if (redirect_stdin)
        {
            clang_stdin.CloseRead();
            __gnu_cxx::stdio_filebuf<char> clang_stdin_buffer(clang_stdin.GetWriteFd(), std::ios::out);
            std::ostream clang_stdin_stream(&clang_stdin_buffer);
            clang_stdin_stream << in->rdbuf();
            clang_stdin.CloseWrite();
        }

        if (redirect_stdout)
        {
            clang_stdout.CloseWrite();
            __gnu_cxx::stdio_filebuf<char> clang_stdout_buffer(clang_stdout.GetReadFd(), std::ios::in);
            std::istream clang_stdin_stream(&clang_stdout_buffer);
            *out << clang_stdin_stream.rdbuf();
            clang_stdout.CloseRead();
        }

        if (waitpid(pid, &wstatus, 0) != pid) { MIOPEN_THROW("Error: X-AMDGCN-ASM: waitpid()"); }
    }

    if (WIFEXITED(wstatus)) {
        const int exit_status = WEXITSTATUS(wstatus);
        return exit_status;
    }
    else {
        MIOPEN_THROW("Error: X-AMDGCN-ASM: clang terminated abnormally");
    }
#else
    (void)p;
    (void)args;
    (void)in;
    (void)out;
    return -1;
#endif // !WIN32
}

int ExecuteGcnAssembler(std::vector<std::string>& args, std::istream* clang_stdin_content, std::ostream* clang_stdout_content)
{
    auto path = GetGcnAssemblerPath();
    return ExecuteGcnAssembler(path, args, clang_stdin_content, clang_stdout_content);
}

static
std::string CleanupPath(const char * p)
{
    std::string path(p);
    static const char bad[] = "!#$*;<>?@\\^`{|}";
    for (char * c = &path[0]; c < (&path[0] + path.length()); ++c) {
        if (std::iscntrl(*c)) {
            *c = '_';
            continue;
        }
        for (const char * b = &bad[0]; b < (&bad[0] + sizeof(bad) - 1); ++b) {
            if (*b == *c) {
                *c = '_';
                break;
            }
        }
    }
    return path;
}
<commit_msg>fixed mac build error<commit_after>#include <miopen/gcn_asm_utils.h>
#include <miopen/errors.hpp>
#include <cstdlib>
#include <cassert>
#include <fstream>
#include <sstream>
#include <cstdio>
#include  <cctype>

#if !defined(_WIN32) && !defined(__APPLE__)
#include <ext/stdio_filebuf.h>
#include <unistd.h>
#include <sys/wait.h>
#endif // !defined(_WIN32) && !defined(__APPLE__)

static std::string CleanupPath(const char * p);
static int ExecuteGcnAssembler(const std::string& p, std::vector<std::string>& args, std::istream* in, std::ostream* out);

#if !defined(_WIN32) && !defined(__APPLE__)
class Pipe
{
public:
    Pipe()
        : _read_side_closed(true)
        , _write_side_closed(true)
    {
    }

    Pipe(Pipe&&) = delete;
    Pipe(Pipe&) = delete;
    Pipe& operator =(Pipe&) = delete;
    ~Pipe() { Close(); }
    void CloseRead() { CloseSide(_read_side, _read_side_closed); }
    void CloseWrite() { CloseSide(_write_side, _write_side_closed); }
    int DupRead(int target_fd) { assert(!_read_side_closed); return dup2(_read_side, target_fd); }
    int DupWrite(int target_fd) { assert(!_write_side_closed); return dup2(_write_side, target_fd); }
    int GetReadFd() { return _read_side; }
    int GetWriteFd() { return _write_side; }

    void Close()
    {
        CloseRead();
        CloseWrite();
    }

    void Open()
    {
        if (pipe(_sides)) { MIOPEN_THROW("Error: pipe()"); }
        _read_side_closed = false;
        _write_side_closed = false;
    }

private:
    union
    {
        int _sides[2];
        struct
        {
            int _read_side;
            int _write_side;
        };
    };

    bool _read_side_closed;
    bool _write_side_closed;

    static void CloseSide(int fd, bool& closed)
    {
        if (closed) { return; }
        if (close(fd)) { std::fprintf(stderr, "Error closing pipe"); }
        closed = true;
    }
};
#endif // !defined(_WIN32) && !defined(__APPLE__)

std::string GetGcnAssemblerPath()
{
    const auto asm_path_env_p = std::getenv("MIOPEN_EXPERIMENTAL_GCN_ASM_PATH");
    if (asm_path_env_p) {
        return CleanupPath(asm_path_env_p);
    }
#ifdef MIOPEN_AMDGCN_ASSEMBLER // string literal generated by CMake
    return CleanupPath(MIOPEN_AMDGCN_ASSEMBLER);
#else
    return "";
#endif
}

bool ValidateGcnAssembler()
{
#if !defined(_WIN32) && !defined(__APPLE__)
    const auto path = GetGcnAssemblerPath();
    if (path.empty()) { return false; }
    if (!std::ifstream(path).good()) { return false; }

    std::vector<std::string> args({"--version"});
    std::stringstream clang_stdout;
    std::string clang_result_line;
    auto clang_rc = ExecuteGcnAssembler(path, args, nullptr, &clang_stdout);

    if (clang_rc != 0) { return false; }

    std::getline(clang_stdout, clang_result_line);
    if (clang_result_line.find("clang") != std::string::npos)

    while (!clang_stdout.eof()) {
        std::getline(clang_stdout, clang_result_line);

        if (clang_result_line.find("Target: ") != std::string::npos) {
            return clang_result_line.find("amdgcn") != std::string::npos;
        }
    }
#endif // !defined(_WIN32) && !defined(__APPLE__)
    return false;
}

static
int ExecuteGcnAssembler(const std::string& p, std::vector<std::string>& args, std::istream* in, std::ostream* out)
{
#if !defined(_WIN32) && !defined(__APPLE__)
    Pipe clang_stdin;
    Pipe clang_stdout;

    const auto redirect_stdin = (in != nullptr);
    const auto redirect_stdout = (out != nullptr);

    if (redirect_stdin) { clang_stdin.Open(); }
    if (redirect_stdout) { clang_stdout.Open(); }

    int wstatus;
    pid_t pid = fork();
    if (pid == 0) {
        std::string path(p); // to remove constness
        std::vector<char*> c_args;
        c_args.push_back(&path[0]);
        for (auto& arg : args) {
            c_args.push_back(&arg[0]);
        }
        c_args.push_back(nullptr);

        if (redirect_stdin) {
            if (clang_stdin.DupRead(STDIN_FILENO) == -1) { std::exit(EXIT_FAILURE); }
            clang_stdin.Close();
        }

        if (redirect_stdout) {
            if (clang_stdout.DupWrite(STDOUT_FILENO) == -1) { std::exit(EXIT_FAILURE); }
            clang_stdout.Close();
        }

        clang_stdout.Close();

        execv(path.c_str(), c_args.data());
        std::exit(EXIT_FAILURE);
    }
    else {
        if (pid == -1) { MIOPEN_THROW("Error X-AMDGCN-ASM: fork()"); }

        if (redirect_stdin)
        {
            clang_stdin.CloseRead();
            __gnu_cxx::stdio_filebuf<char> clang_stdin_buffer(clang_stdin.GetWriteFd(), std::ios::out);
            std::ostream clang_stdin_stream(&clang_stdin_buffer);
            clang_stdin_stream << in->rdbuf();
            clang_stdin.CloseWrite();
        }

        if (redirect_stdout)
        {
            clang_stdout.CloseWrite();
            __gnu_cxx::stdio_filebuf<char> clang_stdout_buffer(clang_stdout.GetReadFd(), std::ios::in);
            std::istream clang_stdin_stream(&clang_stdout_buffer);
            *out << clang_stdin_stream.rdbuf();
            clang_stdout.CloseRead();
        }

        if (waitpid(pid, &wstatus, 0) != pid) { MIOPEN_THROW("Error: X-AMDGCN-ASM: waitpid()"); }
    }

    if (WIFEXITED(wstatus)) {
        const int exit_status = WEXITSTATUS(wstatus);
        return exit_status;
    }
    else {
        MIOPEN_THROW("Error: X-AMDGCN-ASM: clang terminated abnormally");
    }
#else
    (void)p;
    (void)args;
    (void)in;
    (void)out;
    return -1;
#endif // !defined(_WIN32) && !defined(__APPLE__)
}

int ExecuteGcnAssembler(std::vector<std::string>& args, std::istream* clang_stdin_content, std::ostream* clang_stdout_content)
{
    auto path = GetGcnAssemblerPath();
    return ExecuteGcnAssembler(path, args, clang_stdin_content, clang_stdout_content);
}

static
std::string CleanupPath(const char * p)
{
    std::string path(p);
    static const char bad[] = "!#$*;<>?@\\^`{|}";
    for (char * c = &path[0]; c < (&path[0] + path.length()); ++c) {
        if (std::iscntrl(*c)) {
            *c = '_';
            continue;
        }
        for (const char * b = &bad[0]; b < (&bad[0] + sizeof(bad) - 1); ++b) {
            if (*b == *c) {
                *c = '_';
                break;
            }
        }
    }
    return path;
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * This file provides "portable" access to a subset of the stdio.h functions.  By
 * "portable", I mean that using the functions defined here will decrease the
 * pain associated with using these functions in FASTCGI and non-FASTCGI mode.
 *
 * Functions that start with _i_ will use the FCGI_FILE and FCGI_f... functions
 * or FILE and f... functions in FASTCGI mode or non-FASTCGI mode respectively.
 * Use, for example, ifputs() where you would otherwise use fputs(), and it will
 * work in both FASTCGI and non-FASTCGI mode.
 *
 * There is also a set of functions that begin with _g_ that will always use
 * FILE* and standard f... functions from stdio.h.  These are mainly used in
 * response mode type=save-post to write the POST data to a disk file.
 *
 * See @ref ISTDIO_Examples for usage examples.
 */

/**
 * @page ISTDIO_Examples istdio.hpp Examples
 *
 * Look at the following snippet for examples of using _i_ prefixed functions
 * to read from stdin, and _g_ prefixed to open a FILE instead of a FCGI_FILE,
 * and to write using stdin.h functions.
 * @snippet schema.cpp Save_Stdin
 *
 * The following snippet uses _g_ prefixed function stdio.h functions to work with
 * a FILE*, even if the code is compiled in FASTCGI mode.
 * @snippet schema.cpp Write_Multipart_Preamble
 *
 */

#ifndef ISTDIO_HPP_SOURCE
#define ISTDIO_HPP_SOURCE

#include <assert.h>
#include <stdio.h>

#ifdef FASTCGI
#define GFILE FILE

#include <fcgi_stdio.h>
inline int  ifgetc(FCGI_FILE* f)                { return FCGI_fgetc(f); }
inline bool ifeof(FCGI_FILE* f)                 { return FCGI_feof(f); }
inline int  iferror(FCGI_FILE* f)               { return FCGI_ferror(f); }
inline int  ifputs(const char* s, FCGI_FILE* f) { return FCGI_fputs(s,f); }
inline int  ifputc(char c, FCGI_FILE *f)        { return FCGI_fputc(c,f); }
inline size_t ifread(void* bf, size_t s, size_t n, FCGI_FILE *fp)
                                                { return FCGI_fread(bf,s,n,fp); }

void reset_fcgi_streams(void);

// Functions to access global FILE functions after FASTCGI defines
#pragma push_macro("FILE")
#undef FILE

#pragma push_macro("fopen")
#undef fopen
inline FILE* gfopen(const char* path, const char* mode) { return fopen(path,mode); }
#pragma pop_macro("fopen")

#pragma push_macro("fclose")
#undef fclose
inline int gfclose(FILE* f) { return fclose(f); }
#pragma pop_macro("fclose")

#pragma push_macro("feof")
#undef feof
inline int gfeof(FILE* f) { return feof(f); }
#pragma pop_macro("feof")

#pragma push_macro("ferror")
#undef ferror
inline int gferror(FILE* f)  { return ferror(f); }
#pragma pop_macro("ferror")

#pragma push_macro("fputs")
#undef fputs
inline int gfputs(const char *s, FILE* f) { return fputs(s,f); }
#pragma pop_macro("fputs")

#pragma push_macro("fwrite")
#undef fwrite
inline size_t gfwrite(void* ptr, size_t size, size_t nmemb, FILE *fp)
{
   return fwrite(ptr,size,nmemb,fp);
}
#pragma pop_macro("fwrite")

#pragma pop_macro("FILE")

// Implemented in istdio.cpp to avoid macro renaming
// FCGI_FILE *ifopen(const char *path, const char *mode, FCGI_FILE &f);
// int ifclose(FCGI_FILE &f);
int ifprintf(FCGI_FILE* f, const char *format, ...);

#else   //  ifndef FASTCGI
inline int  ifgetc(FILE* f)                { return fgetc(f); }
inline bool ifeof(FILE* f)                 { return feof(f); }
inline int  iferror(FILE* f)               { return ferror(f); }
inline int  ifputs(const char* s, FILE* f) { return fputs(s,f); }
inline int  ifputc(char c, FILE *f)        { return fputc(c,f); }
inline size_t ifread(void* bf, size_t s, size_t n, FILE *fp)
                                           { return fread(bf,s,n,fp); }

void reset_fcgi_streams(void)              { ; }

inline FILE *gfopen(const char* path, const char* mode) { return fopen(path,mode); }
inline int gfclose(FILE* f) { return fclose(f); }
inline int gfeof(FILE* f)   { return feof(f); }
inline int gferror(FILE* f)   { return ferror(f); }
inline int gfputs(const char *s, FILE* f) { return fputs(s,f); }
inline size_t gfwrite(void* ptr, size_t size, size_t nmemb, FILE *fp)
{
   return fwrite(ptr,size,nmemb,fp);
}

// Implementions of same named function in ifdef FASTCGI section above:
int  ifprintf(FILE* f, const char *format, ...);
#endif   // ifdef FASTCGI

#endif
<commit_msg>Added get_null_FILE() function to generate an unassigned FILE* when FCGI is defined.<commit_after>/**
 * @file
 *
 * This file provides "portable" access to a subset of the stdio.h functions.  By
 * "portable", I mean that using the functions defined here will decrease the
 * pain associated with using these functions in FASTCGI and non-FASTCGI mode.
 *
 * Functions that start with _i_ will use the FCGI_FILE and FCGI_f... functions
 * or FILE and f... functions in FASTCGI mode or non-FASTCGI mode respectively.
 * Use, for example, ifputs() where you would otherwise use fputs(), and it will
 * work in both FASTCGI and non-FASTCGI mode.
 *
 * There is also a set of functions that begin with _g_ that will always use
 * FILE* and standard f... functions from stdio.h.  These are mainly used in
 * response mode type=save-post to write the POST data to a disk file.
 *
 * See @ref ISTDIO_Examples for usage examples.
 */

/**
 * @page ISTDIO_Examples istdio.hpp Examples
 *
 * Look at the following snippet for examples of using _i_ prefixed functions
 * to read from stdin, and _g_ prefixed to open a FILE instead of a FCGI_FILE,
 * and to write using stdin.h functions.
 * @snippet schema.cpp Save_Stdin
 *
 * The following snippet uses _g_ prefixed function stdio.h functions to work with
 * a FILE*, even if the code is compiled in FASTCGI mode.
 * @snippet schema.cpp Write_Multipart_Preamble
 *
 */

#ifndef ISTDIO_HPP_SOURCE
#define ISTDIO_HPP_SOURCE

#include <assert.h>
#include <stdio.h>

#ifdef FASTCGI

#include <fcgi_stdio.h>
inline int  ifgetc(FCGI_FILE* f)                { return FCGI_fgetc(f); }
inline bool ifeof(FCGI_FILE* f)                 { return FCGI_feof(f); }
inline int  iferror(FCGI_FILE* f)               { return FCGI_ferror(f); }
inline int  ifputs(const char* s, FCGI_FILE* f) { return FCGI_fputs(s,f); }
inline int  ifputc(char c, FCGI_FILE *f)        { return FCGI_fputc(c,f); }
inline size_t ifread(void* bf, size_t s, size_t n, FCGI_FILE *fp)
                                                { return FCGI_fread(bf,s,n,fp); }

void reset_fcgi_streams(void);

// Functions to access global FILE functions after FASTCGI defines
#pragma push_macro("FILE")
#undef FILE

/**
 * @brief Returns a stdio.h FILE*, even if fcgi_stdio.h has redefined it.
 *
 * This function is sometimes necessary in order to use stdio.h functions that
 * have not been converted to FCGI_FILE.  It was added to work with dup2().
 *
 * usage:
 * `auto* f = get_null_FILE();`
 */
inline FILE* get_null_FILE(void) { return static_cast<FILE*>(nullptr); }

#pragma push_macro("fopen")
#undef fopen
inline FILE* gfopen(const char* path, const char* mode) { return fopen(path,mode); }
#pragma pop_macro("fopen")

#pragma push_macro("fclose")
#undef fclose
inline int gfclose(FILE* f) { return fclose(f); }
#pragma pop_macro("fclose")

#pragma push_macro("feof")
#undef feof
inline int gfeof(FILE* f) { return feof(f); }
#pragma pop_macro("feof")

#pragma push_macro("ferror")
#undef ferror
inline int gferror(FILE* f)  { return ferror(f); }
#pragma pop_macro("ferror")

#pragma push_macro("fputs")
#undef fputs
inline int gfputs(const char *s, FILE* f) { return fputs(s,f); }
#pragma pop_macro("fputs")

#pragma push_macro("fwrite")
#undef fwrite
inline size_t gfwrite(void* ptr, size_t size, size_t nmemb, FILE *fp)
{
   return fwrite(ptr,size,nmemb,fp);
}
#pragma pop_macro("fwrite")

#pragma pop_macro("FILE")

// Implemented in istdio.cpp to avoid macro renaming
// FCGI_FILE *ifopen(const char *path, const char *mode, FCGI_FILE &f);
// int ifclose(FCGI_FILE &f);
int ifprintf(FCGI_FILE* f, const char *format, ...);

#else   //  ifndef FASTCGI
inline int  ifgetc(FILE* f)                { return fgetc(f); }
inline bool ifeof(FILE* f)                 { return feof(f); }
inline int  iferror(FILE* f)               { return ferror(f); }
inline int  ifputs(const char* s, FILE* f) { return fputs(s,f); }
inline int  ifputc(char c, FILE *f)        { return fputc(c,f); }
inline size_t ifread(void* bf, size_t s, size_t n, FILE *fp)
                                           { return fread(bf,s,n,fp); }

void reset_fcgi_streams(void)              { ; }

inline FILE *gfopen(const char* path, const char* mode) { return fopen(path,mode); }
inline int gfclose(FILE* f) { return fclose(f); }
inline int gfeof(FILE* f)   { return feof(f); }
inline int gferror(FILE* f)   { return ferror(f); }
inline int gfputs(const char *s, FILE* f) { return fputs(s,f); }
inline size_t gfwrite(void* ptr, size_t size, size_t nmemb, FILE *fp)
{
   return fwrite(ptr,size,nmemb,fp);
}

// Implementions of same named function in ifdef FASTCGI section above:
int  ifprintf(FILE* f, const char *format, ...);
#endif   // ifdef FASTCGI

#endif
<|endoftext|>


<commit_before>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Google Inc. 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 <limits>
#include <sstream>

#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/wire_format.h>

#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>

using google::protobuf::internal::scoped_ptr;

namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {

void FieldGeneratorBase::SetCommonFieldVariables(
    map<string, string>* variables) {
  // Note: this will be valid even though the tag emitted for packed and unpacked versions of
  // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
  // never effects the tag size.
  int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
  uint tag = internal::WireFormat::MakeTag(descriptor_);
  uint8 tag_array[5];
  io::CodedOutputStream::WriteTagToArray(tag, tag_array);
  string tag_bytes = SimpleItoa(tag_array[0]);
  for (int i = 1; i < tag_size; i++) {
    tag_bytes += ", " + SimpleItoa(tag_array[i]);
  }

  (*variables)["access_level"] = "public";
  (*variables)["tag"] = SimpleItoa(tag);
  (*variables)["tag_size"] = SimpleItoa(tag_size);
  (*variables)["tag_bytes"] = tag_bytes;

  (*variables)["property_name"] = property_name();
  (*variables)["type_name"] = type_name();
  (*variables)["name"] = name();
  (*variables)["descriptor_name"] = descriptor_->name();
  (*variables)["default_value"] = default_value();
  if (has_default_value()) {
    (*variables)["name_def_message"] =
      (*variables)["name"] + "_ = " + (*variables)["default_value"];
  } else {
    (*variables)["name_def_message"] = (*variables)["name"] + "_";
  }
  (*variables)["capitalized_type_name"] = capitalized_type_name();
  (*variables)["number"] = number();
  (*variables)["has_property_check"] =
    (*variables)["property_name"] + " != " + (*variables)["default_value"];
  (*variables)["other_has_property_check"] = "other." +
    (*variables)["property_name"] + " != " + (*variables)["default_value"];
}

void FieldGeneratorBase::SetCommonOneofFieldVariables(
    map<string, string>* variables) {
  (*variables)["oneof_name"] = oneof_name();
  (*variables)["has_property_check"] =
    oneof_name() + "Case_ == " + oneof_property_name() +
    "OneofCase." + property_name();
  (*variables)["oneof_property_name"] = oneof_property_name();
}

FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
                                       int fieldOrdinal, const Options* options)
    : SourceGeneratorBase(descriptor->file(), options),
      descriptor_(descriptor),
      fieldOrdinal_(fieldOrdinal) {
  SetCommonFieldVariables(&variables_);
}

FieldGeneratorBase::~FieldGeneratorBase() {
}

void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
  // No-op: only message fields and repeated fields need
  // special handling for freezing, so default to not generating any code.
}

void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
    // No-op: expect this to be overridden by appropriate types.
    // Could fail if we get called here though...
}

void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
  if (descriptor_->options().deprecated())
  {
    printer->Print("[global::System.ObsoleteAttribute()]\n");
  }
}

void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
  AddDeprecatedFlag(printer);
}

std::string FieldGeneratorBase::oneof_property_name() {
  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
}

std::string FieldGeneratorBase::oneof_name() {
  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
}

std::string FieldGeneratorBase::property_name() {
  return GetPropertyName(descriptor_);
}

std::string FieldGeneratorBase::name() {
  return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
}

std::string FieldGeneratorBase::type_name() {
  return type_name(descriptor_);
}

std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_ENUM:
      return GetClassName(descriptor->enum_type());
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      if (IsWrapperType(descriptor)) {
        const FieldDescriptor* wrapped_field =
            descriptor->message_type()->field(0);
        string wrapped_field_type_name = type_name(wrapped_field);
        // String and ByteString go to the same type; other wrapped types
        // go to the nullable equivalent.
        if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
            wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
          return wrapped_field_type_name;
        } else {
          return wrapped_field_type_name + "?";
        }
      }
      return GetClassName(descriptor->message_type());
    case FieldDescriptor::TYPE_DOUBLE:
      return "double";
    case FieldDescriptor::TYPE_FLOAT:
      return "float";
    case FieldDescriptor::TYPE_INT64:
      return "long";
    case FieldDescriptor::TYPE_UINT64:
      return "ulong";
    case FieldDescriptor::TYPE_INT32:
      return "int";
    case FieldDescriptor::TYPE_FIXED64:
      return "ulong";
    case FieldDescriptor::TYPE_FIXED32:
      return "uint";
    case FieldDescriptor::TYPE_BOOL:
      return "bool";
    case FieldDescriptor::TYPE_STRING:
      return "string";
    case FieldDescriptor::TYPE_BYTES:
      return "pb::ByteString";
    case FieldDescriptor::TYPE_UINT32:
      return "uint";
    case FieldDescriptor::TYPE_SFIXED32:
      return "int";
    case FieldDescriptor::TYPE_SFIXED64:
      return "long";
    case FieldDescriptor::TYPE_SINT32:
      return "int";
    case FieldDescriptor::TYPE_SINT64:
      return "long";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

bool FieldGeneratorBase::has_default_value() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      return true;
    case FieldDescriptor::TYPE_DOUBLE:
      return descriptor_->default_value_double() != 0.0;
    case FieldDescriptor::TYPE_FLOAT:
      return descriptor_->default_value_float() != 0.0;
    case FieldDescriptor::TYPE_INT64:
      return descriptor_->default_value_int64() != 0L;
    case FieldDescriptor::TYPE_UINT64:
      return descriptor_->default_value_uint64() != 0L;
    case FieldDescriptor::TYPE_INT32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_FIXED64:
      return descriptor_->default_value_uint64() != 0L;
    case FieldDescriptor::TYPE_FIXED32:
      return descriptor_->default_value_uint32() != 0;
    case FieldDescriptor::TYPE_BOOL:
      return descriptor_->default_value_bool();
    case FieldDescriptor::TYPE_STRING:
      return true;
    case FieldDescriptor::TYPE_BYTES:
      return true;
    case FieldDescriptor::TYPE_UINT32:
      return descriptor_->default_value_uint32() != 0;
    case FieldDescriptor::TYPE_SFIXED32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_SFIXED64:
      return descriptor_->default_value_int64() != 0L;
    case FieldDescriptor::TYPE_SINT32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_SINT64:
      return descriptor_->default_value_int64() != 0L;
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return true;
  }
}

bool FieldGeneratorBase::is_nullable_type() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
    case FieldDescriptor::TYPE_DOUBLE:
    case FieldDescriptor::TYPE_FLOAT:
    case FieldDescriptor::TYPE_INT64:
    case FieldDescriptor::TYPE_UINT64:
    case FieldDescriptor::TYPE_INT32:
    case FieldDescriptor::TYPE_FIXED64:
    case FieldDescriptor::TYPE_FIXED32:
    case FieldDescriptor::TYPE_BOOL:
    case FieldDescriptor::TYPE_UINT32:
    case FieldDescriptor::TYPE_SFIXED32:
    case FieldDescriptor::TYPE_SFIXED64:
    case FieldDescriptor::TYPE_SINT32:
    case FieldDescriptor::TYPE_SINT64:
      return false;

    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
    case FieldDescriptor::TYPE_STRING:
    case FieldDescriptor::TYPE_BYTES:
      return true;

    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return true;
  }
}

bool AllPrintableAscii(const std::string& text) {
  for(int i = 0; i < text.size(); i++) {
    if (text[i] < 0x20 || text[i] > 0x7e) {
      return false;
    }
  }
  return true;
}

std::string FieldGeneratorBase::GetStringDefaultValueInternal() {
  // No other default values needed for proto3...
  return "\"\"";
}

std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
  // No other default values needed for proto3...
  return "pb::ByteString.Empty";
}

std::string FieldGeneratorBase::default_value() {
    return default_value(descriptor_);
}

std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_ENUM:
      return type_name() + "." + descriptor->default_value_enum()->name();
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      if (IsWrapperType(descriptor)) {
        const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
        return default_value(wrapped_field);
      } else {
        return "null";
      }
    case FieldDescriptor::TYPE_DOUBLE: {
      double value = descriptor->default_value_double();
      if (value == numeric_limits<double>::infinity()) {
        return "double.PositiveInfinity";
      } else if (value == -numeric_limits<double>::infinity()) {
        return "double.NegativeInfinity";
      } else if (MathLimits<double>::IsNaN(value)) {
        return "double.NaN";
      }
      return SimpleDtoa(value) + "D";
    }
    case FieldDescriptor::TYPE_FLOAT: {
      float value = descriptor->default_value_float();
      if (value == numeric_limits<float>::infinity()) {
        return "float.PositiveInfinity";
      } else if (value == -numeric_limits<float>::infinity()) {
        return "float.NegativeInfinity";
      } else if (MathLimits<float>::IsNaN(value)) {
        return "float.NaN";
      }
      return SimpleFtoa(value) + "F";
    }
    case FieldDescriptor::TYPE_INT64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    case FieldDescriptor::TYPE_UINT64:
      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
    case FieldDescriptor::TYPE_INT32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_FIXED64:
      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
    case FieldDescriptor::TYPE_FIXED32:
      return SimpleItoa(descriptor->default_value_uint32());
    case FieldDescriptor::TYPE_BOOL:
      if (descriptor->default_value_bool()) {
        return "true";
      } else {
        return "false";
      }
    case FieldDescriptor::TYPE_STRING:
      return GetStringDefaultValueInternal();
    case FieldDescriptor::TYPE_BYTES:
      return GetBytesDefaultValueInternal();
    case FieldDescriptor::TYPE_UINT32:
      return SimpleItoa(descriptor->default_value_uint32());
    case FieldDescriptor::TYPE_SFIXED32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_SFIXED64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    case FieldDescriptor::TYPE_SINT32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_SINT64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

std::string FieldGeneratorBase::number() {
  return SimpleItoa(descriptor_->number());
}

std::string FieldGeneratorBase::capitalized_type_name() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
      return "Enum";
    case FieldDescriptor::TYPE_MESSAGE:
      return "Message";
    case FieldDescriptor::TYPE_GROUP:
      return "Group";
    case FieldDescriptor::TYPE_DOUBLE:
      return "Double";
    case FieldDescriptor::TYPE_FLOAT:
      return "Float";
    case FieldDescriptor::TYPE_INT64:
      return "Int64";
    case FieldDescriptor::TYPE_UINT64:
      return "UInt64";
    case FieldDescriptor::TYPE_INT32:
      return "Int32";
    case FieldDescriptor::TYPE_FIXED64:
      return "Fixed64";
    case FieldDescriptor::TYPE_FIXED32:
      return "Fixed32";
    case FieldDescriptor::TYPE_BOOL:
      return "Bool";
    case FieldDescriptor::TYPE_STRING:
      return "String";
    case FieldDescriptor::TYPE_BYTES:
      return "Bytes";
    case FieldDescriptor::TYPE_UINT32:
      return "UInt32";
    case FieldDescriptor::TYPE_SFIXED32:
      return "SFixed32";
    case FieldDescriptor::TYPE_SFIXED64:
      return "SFixed64";
    case FieldDescriptor::TYPE_SINT32:
      return "SInt32";
    case FieldDescriptor::TYPE_SINT64:
      return "SInt64";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

}  // namespace csharp
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<commit_msg>Use 0 as the default value for all enums, rather than finding the actual enum value name<commit_after>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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 Google Inc. 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 <limits>
#include <sstream>

#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/wire_format.h>

#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_names.h>

using google::protobuf::internal::scoped_ptr;

namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {

void FieldGeneratorBase::SetCommonFieldVariables(
    map<string, string>* variables) {
  // Note: this will be valid even though the tag emitted for packed and unpacked versions of
  // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
  // never effects the tag size.
  int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
  uint tag = internal::WireFormat::MakeTag(descriptor_);
  uint8 tag_array[5];
  io::CodedOutputStream::WriteTagToArray(tag, tag_array);
  string tag_bytes = SimpleItoa(tag_array[0]);
  for (int i = 1; i < tag_size; i++) {
    tag_bytes += ", " + SimpleItoa(tag_array[i]);
  }

  (*variables)["access_level"] = "public";
  (*variables)["tag"] = SimpleItoa(tag);
  (*variables)["tag_size"] = SimpleItoa(tag_size);
  (*variables)["tag_bytes"] = tag_bytes;

  (*variables)["property_name"] = property_name();
  (*variables)["type_name"] = type_name();
  (*variables)["name"] = name();
  (*variables)["descriptor_name"] = descriptor_->name();
  (*variables)["default_value"] = default_value();
  if (has_default_value()) {
    (*variables)["name_def_message"] =
      (*variables)["name"] + "_ = " + (*variables)["default_value"];
  } else {
    (*variables)["name_def_message"] = (*variables)["name"] + "_";
  }
  (*variables)["capitalized_type_name"] = capitalized_type_name();
  (*variables)["number"] = number();
  (*variables)["has_property_check"] =
    (*variables)["property_name"] + " != " + (*variables)["default_value"];
  (*variables)["other_has_property_check"] = "other." +
    (*variables)["property_name"] + " != " + (*variables)["default_value"];
}

void FieldGeneratorBase::SetCommonOneofFieldVariables(
    map<string, string>* variables) {
  (*variables)["oneof_name"] = oneof_name();
  (*variables)["has_property_check"] =
    oneof_name() + "Case_ == " + oneof_property_name() +
    "OneofCase." + property_name();
  (*variables)["oneof_property_name"] = oneof_property_name();
}

FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
                                       int fieldOrdinal, const Options* options)
    : SourceGeneratorBase(descriptor->file(), options),
      descriptor_(descriptor),
      fieldOrdinal_(fieldOrdinal) {
  SetCommonFieldVariables(&variables_);
}

FieldGeneratorBase::~FieldGeneratorBase() {
}

void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
  // No-op: only message fields and repeated fields need
  // special handling for freezing, so default to not generating any code.
}

void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
    // No-op: expect this to be overridden by appropriate types.
    // Could fail if we get called here though...
}

void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
  if (descriptor_->options().deprecated())
  {
    printer->Print("[global::System.ObsoleteAttribute()]\n");
  }
}

void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
  AddDeprecatedFlag(printer);
}

std::string FieldGeneratorBase::oneof_property_name() {
  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
}

std::string FieldGeneratorBase::oneof_name() {
  return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
}

std::string FieldGeneratorBase::property_name() {
  return GetPropertyName(descriptor_);
}

std::string FieldGeneratorBase::name() {
  return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
}

std::string FieldGeneratorBase::type_name() {
  return type_name(descriptor_);
}

std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_ENUM:
      return GetClassName(descriptor->enum_type());
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      if (IsWrapperType(descriptor)) {
        const FieldDescriptor* wrapped_field =
            descriptor->message_type()->field(0);
        string wrapped_field_type_name = type_name(wrapped_field);
        // String and ByteString go to the same type; other wrapped types
        // go to the nullable equivalent.
        if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
            wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
          return wrapped_field_type_name;
        } else {
          return wrapped_field_type_name + "?";
        }
      }
      return GetClassName(descriptor->message_type());
    case FieldDescriptor::TYPE_DOUBLE:
      return "double";
    case FieldDescriptor::TYPE_FLOAT:
      return "float";
    case FieldDescriptor::TYPE_INT64:
      return "long";
    case FieldDescriptor::TYPE_UINT64:
      return "ulong";
    case FieldDescriptor::TYPE_INT32:
      return "int";
    case FieldDescriptor::TYPE_FIXED64:
      return "ulong";
    case FieldDescriptor::TYPE_FIXED32:
      return "uint";
    case FieldDescriptor::TYPE_BOOL:
      return "bool";
    case FieldDescriptor::TYPE_STRING:
      return "string";
    case FieldDescriptor::TYPE_BYTES:
      return "pb::ByteString";
    case FieldDescriptor::TYPE_UINT32:
      return "uint";
    case FieldDescriptor::TYPE_SFIXED32:
      return "int";
    case FieldDescriptor::TYPE_SFIXED64:
      return "long";
    case FieldDescriptor::TYPE_SINT32:
      return "int";
    case FieldDescriptor::TYPE_SINT64:
      return "long";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

bool FieldGeneratorBase::has_default_value() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      return true;
    case FieldDescriptor::TYPE_DOUBLE:
      return descriptor_->default_value_double() != 0.0;
    case FieldDescriptor::TYPE_FLOAT:
      return descriptor_->default_value_float() != 0.0;
    case FieldDescriptor::TYPE_INT64:
      return descriptor_->default_value_int64() != 0L;
    case FieldDescriptor::TYPE_UINT64:
      return descriptor_->default_value_uint64() != 0L;
    case FieldDescriptor::TYPE_INT32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_FIXED64:
      return descriptor_->default_value_uint64() != 0L;
    case FieldDescriptor::TYPE_FIXED32:
      return descriptor_->default_value_uint32() != 0;
    case FieldDescriptor::TYPE_BOOL:
      return descriptor_->default_value_bool();
    case FieldDescriptor::TYPE_STRING:
      return true;
    case FieldDescriptor::TYPE_BYTES:
      return true;
    case FieldDescriptor::TYPE_UINT32:
      return descriptor_->default_value_uint32() != 0;
    case FieldDescriptor::TYPE_SFIXED32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_SFIXED64:
      return descriptor_->default_value_int64() != 0L;
    case FieldDescriptor::TYPE_SINT32:
      return descriptor_->default_value_int32() != 0;
    case FieldDescriptor::TYPE_SINT64:
      return descriptor_->default_value_int64() != 0L;
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return true;
  }
}

bool FieldGeneratorBase::is_nullable_type() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
    case FieldDescriptor::TYPE_DOUBLE:
    case FieldDescriptor::TYPE_FLOAT:
    case FieldDescriptor::TYPE_INT64:
    case FieldDescriptor::TYPE_UINT64:
    case FieldDescriptor::TYPE_INT32:
    case FieldDescriptor::TYPE_FIXED64:
    case FieldDescriptor::TYPE_FIXED32:
    case FieldDescriptor::TYPE_BOOL:
    case FieldDescriptor::TYPE_UINT32:
    case FieldDescriptor::TYPE_SFIXED32:
    case FieldDescriptor::TYPE_SFIXED64:
    case FieldDescriptor::TYPE_SINT32:
    case FieldDescriptor::TYPE_SINT64:
      return false;

    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
    case FieldDescriptor::TYPE_STRING:
    case FieldDescriptor::TYPE_BYTES:
      return true;

    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return true;
  }
}

bool AllPrintableAscii(const std::string& text) {
  for(int i = 0; i < text.size(); i++) {
    if (text[i] < 0x20 || text[i] > 0x7e) {
      return false;
    }
  }
  return true;
}

std::string FieldGeneratorBase::GetStringDefaultValueInternal() {
  // No other default values needed for proto3...
  return "\"\"";
}

std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
  // No other default values needed for proto3...
  return "pb::ByteString.Empty";
}

std::string FieldGeneratorBase::default_value() {
    return default_value(descriptor_);
}

std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_ENUM:
      // All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to
      // any C# enum. This means we don't need to work out what we actually mapped the enum value name to.
     return "0";
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_GROUP:
      if (IsWrapperType(descriptor)) {
        const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
        return default_value(wrapped_field);
      } else {
        return "null";
      }
    case FieldDescriptor::TYPE_DOUBLE: {
      double value = descriptor->default_value_double();
      if (value == numeric_limits<double>::infinity()) {
        return "double.PositiveInfinity";
      } else if (value == -numeric_limits<double>::infinity()) {
        return "double.NegativeInfinity";
      } else if (MathLimits<double>::IsNaN(value)) {
        return "double.NaN";
      }
      return SimpleDtoa(value) + "D";
    }
    case FieldDescriptor::TYPE_FLOAT: {
      float value = descriptor->default_value_float();
      if (value == numeric_limits<float>::infinity()) {
        return "float.PositiveInfinity";
      } else if (value == -numeric_limits<float>::infinity()) {
        return "float.NegativeInfinity";
      } else if (MathLimits<float>::IsNaN(value)) {
        return "float.NaN";
      }
      return SimpleFtoa(value) + "F";
    }
    case FieldDescriptor::TYPE_INT64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    case FieldDescriptor::TYPE_UINT64:
      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
    case FieldDescriptor::TYPE_INT32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_FIXED64:
      return SimpleItoa(descriptor->default_value_uint64()) + "UL";
    case FieldDescriptor::TYPE_FIXED32:
      return SimpleItoa(descriptor->default_value_uint32());
    case FieldDescriptor::TYPE_BOOL:
      if (descriptor->default_value_bool()) {
        return "true";
      } else {
        return "false";
      }
    case FieldDescriptor::TYPE_STRING:
      return GetStringDefaultValueInternal();
    case FieldDescriptor::TYPE_BYTES:
      return GetBytesDefaultValueInternal();
    case FieldDescriptor::TYPE_UINT32:
      return SimpleItoa(descriptor->default_value_uint32());
    case FieldDescriptor::TYPE_SFIXED32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_SFIXED64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    case FieldDescriptor::TYPE_SINT32:
      return SimpleItoa(descriptor->default_value_int32());
    case FieldDescriptor::TYPE_SINT64:
      return SimpleItoa(descriptor->default_value_int64()) + "L";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

std::string FieldGeneratorBase::number() {
  return SimpleItoa(descriptor_->number());
}

std::string FieldGeneratorBase::capitalized_type_name() {
  switch (descriptor_->type()) {
    case FieldDescriptor::TYPE_ENUM:
      return "Enum";
    case FieldDescriptor::TYPE_MESSAGE:
      return "Message";
    case FieldDescriptor::TYPE_GROUP:
      return "Group";
    case FieldDescriptor::TYPE_DOUBLE:
      return "Double";
    case FieldDescriptor::TYPE_FLOAT:
      return "Float";
    case FieldDescriptor::TYPE_INT64:
      return "Int64";
    case FieldDescriptor::TYPE_UINT64:
      return "UInt64";
    case FieldDescriptor::TYPE_INT32:
      return "Int32";
    case FieldDescriptor::TYPE_FIXED64:
      return "Fixed64";
    case FieldDescriptor::TYPE_FIXED32:
      return "Fixed32";
    case FieldDescriptor::TYPE_BOOL:
      return "Bool";
    case FieldDescriptor::TYPE_STRING:
      return "String";
    case FieldDescriptor::TYPE_BYTES:
      return "Bytes";
    case FieldDescriptor::TYPE_UINT32:
      return "UInt32";
    case FieldDescriptor::TYPE_SFIXED32:
      return "SFixed32";
    case FieldDescriptor::TYPE_SFIXED64:
      return "SFixed64";
    case FieldDescriptor::TYPE_SINT32:
      return "SInt32";
    case FieldDescriptor::TYPE_SINT64:
      return "SInt64";
    default:
      GOOGLE_LOG(FATAL)<< "Unknown field type.";
      return "";
  }
}

}  // namespace csharp
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<|endoftext|>


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

#include "omxData.h"
#include <Eigen/Core>
// #include <Eigen/Dense>
#include "EnableWarnings.h"

struct omxWLSFitFunction : omxFitFunction {

	omxMatrix* expectedCov;
	omxMatrix* expectedMeans;
	omxMatrix* expectedSlope;
	omxMatrix* observedFlattened;
	omxMatrix* expectedFlattened;
	omxMatrix* P;
	omxMatrix* B;
	int numOrdinal;
	int vectorSize;

	const char *type;
	const char *continuousType;
	bool fullWeight;

	omxWLSFitFunction() :
		type("WLS"), continuousType("cumulants"), fullWeight(true) {};
	virtual ~omxWLSFitFunction();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);

	void flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *slope, omxMatrix *thresholdMat,
				 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector);
	void prepData();
	virtual void invalidateCache()
	{
		omxFreeMatrix(observedFlattened);
		observedFlattened = 0;
	}
};

void omxWLSFitFunction::flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *slope,
					    omxMatrix *thresholdMat,
			 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector)
{
	EigenVectorAdaptor vec1(vector);
	normalToStdVector(cov, means, slope, thresholdMat, numOrdinal, thresholds, vec1);
}

omxWLSFitFunction::~omxWLSFitFunction()
{
	if(OMX_DEBUG) {mxLog("Freeing WLS FitFunction.");}

	invalidateCache();
	omxWLSFitFunction* owo = this;
	omxFreeMatrix(owo->expectedFlattened);
	omxFreeMatrix(owo->B);
	omxFreeMatrix(owo->P);
}

void omxWLSFitFunction::compute(int want, FitContext *fc)
{
	auto *oo = this;
	auto *owo = this;
	if (want & FF_COMPUTE_INITIAL_FIT) return;
	if ((want & FF_COMPUTE_PREOPTIMIZE) && !observedFlattened) {
		prepData();
		return;
	}

	if(OMX_DEBUG) { mxLog("Beginning WLS Evaluation.");}
	// Requires: Data, means, covariances.

	double sum = 0.0;

	omxMatrix *eCov, *eMeans, *oFlat, *eFlat;

	/* Locals for readability.  Compiler should cut through this. */
	eCov		= owo->expectedCov;
	eMeans 		= owo->expectedMeans;
	auto &eThresh   = oo->expectation->getThresholdInfo();
	if (!observedFlattened) return;
	oFlat		= observedFlattened;
	eFlat		= owo->expectedFlattened;
	int onei	= 1;

	/* Recompute and recopy */
	if(OMX_DEBUG) { mxLog("WLSFitFunction Computing expectation"); }
	omxExpectationCompute(fc, expectation, NULL);

	omxMatrix *expThresholdsMat = expectation->thresholdsMat;

	flattenDataToVector(eCov, eMeans, expectedSlope, expThresholdsMat, eThresh, eFlat);

	omxCopyMatrix(B, oFlat);

	if(OMX_DEBUG) {omxPrintMatrix(eFlat, "....WLS Expected Vector: "); }
	omxDAXPY(-1.0, eFlat, B);
	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed - Expected Vector: "); }

	omxMatrix *weights = expectation->data->getSingleObsSummaryStats().acovMat;
	if(weights != NULL) {
		//if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weights, "....WLS Weight Matrix: "); }
		omxDGEMV(TRUE, 1.0, weights, B, 0.0, P);
	} else {
		// ULS Case: Memcpy faster than dgemv.
		omxCopyMatrix(P, B);
		omxTransposeMatrix(P);
	}

	sum = F77_CALL(ddot)(&(P->cols), P->data, &onei, B->data, &onei);

	oo->matrix->data[0] = sum;

	if(OMX_DEBUG) { mxLog("WLSFitFunction value comes to: %f.", oo->matrix->data[0]); }

}

void omxWLSFitFunction::populateAttr(SEXP algebra)
{
	if(OMX_DEBUG) { mxLog("Populating WLS Attributes."); }

	omxWLSFitFunction *argStruct = this;
	omxMatrix *expCovInt = argStruct->expectedCov;	    		// Expected covariance
	omxMatrix *expMeanInt = argStruct->expectedMeans;			// Expected means
	omxMatrix *weightInt = expectation->data->getSingleObsSummaryStats().acovMat;

	SEXP expCovExt, expMeanExt, gradients;
	Rf_protect(expCovExt = Rf_allocMatrix(REALSXP, expCovInt->rows, expCovInt->cols));
	for(int row = 0; row < expCovInt->rows; row++)
		for(int col = 0; col < expCovInt->cols; col++)
			REAL(expCovExt)[col * expCovInt->rows + row] =
				omxMatrixElement(expCovInt, row, col);

	if (expMeanInt != NULL) {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, expMeanInt->rows, expMeanInt->cols));
		for(int row = 0; row < expMeanInt->rows; row++)
			for(int col = 0; col < expMeanInt->cols; col++)
				REAL(expMeanExt)[col * expMeanInt->rows + row] =
					omxMatrixElement(expMeanInt, row, col);
	} else {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weightInt, "...WLS Weight Matrix: W"); }
	SEXP weightExt = NULL;
	if (weightInt) {
		Rf_protect(weightExt = Rf_allocMatrix(REALSXP, weightInt->rows, weightInt->cols));
		for(int row = 0; row < weightInt->rows; row++)
			for(int col = 0; col < weightInt->cols; col++)
				REAL(weightExt)[col * weightInt->rows + row] = weightInt->data[col * weightInt->rows + row];
	}

	if(0) {  /* TODO fix for new internal API
		int nLocs = Global->numFreeParams;
		double gradient[Global->numFreeParams];
		for(int loc = 0; loc < nLocs; loc++) {
			gradient[loc] = NA_REAL;
		}
		//oo->gradientFun(oo, gradient);
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 1, nLocs));

		for(int loc = 0; loc < nLocs; loc++)
			REAL(gradients)[loc] = gradient[loc];
		 */
	} else {
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG) { mxLog("Installing populated WLS Attributes."); }
	Rf_setAttrib(algebra, Rf_install("expCov"), expCovExt);
	Rf_setAttrib(algebra, Rf_install("expMean"), expMeanExt);
	if (weightExt) Rf_setAttrib(algebra, Rf_install("weights"), weightExt);
	Rf_setAttrib(algebra, Rf_install("gradients"), gradients);

	ProtectedSEXP Rsat(Rf_ScalarReal(0));
	Rf_setAttrib(algebra, Rf_install("SaturatedLikelihood"), Rsat);
	//Rf_setAttrib(algebra, Rf_install("IndependenceLikelihood"), Rf_ScalarReal(0));
	ProtectedSEXP Rmisfit(Rf_ScalarReal(omxMatrixElement(matrix, 0, 0)));
	Rf_setAttrib(algebra, Rf_install("ADFMisfit"), Rmisfit);
}

omxFitFunction *omxInitWLSFitFunction()
{ return new omxWLSFitFunction; }

void omxWLSFitFunction::prepData()
{
	auto *oo = this;
	auto *newObj = this;

	if (vectorSize != expectation->numSummaryStats())
		mxThrow("%s: vectorSize changed from %d -> %d",
			name(), vectorSize, expectation->numSummaryStats());

	omxData* dataMat = oo->expectation->data;

	if (!matrix->currentState->isClone()) {
		std::vector<int> exoPred;
		expectation->getExogenousPredictors(exoPred);
		// how to prohibit def vars? TODO

		dataMat->prepObsStats(matrix->currentState, expectation->getDataColumnNames(),
				      exoPred, type, continuousType, fullWeight);
		if (isErrorRaised()) return;
	}

	auto &obsStat = dataMat->getSingleObsSummaryStats();
	//obsStat.log();
	omxMatrix *cov = obsStat.covMat;
	if (!cov) {
		omxRaiseErrorf("%s: an observed covariance matrix is required", name());
		return;
	}

	omxMatrix *means = obsStat.meansMat;
	omxMatrix *obsThresholdsMat = obsStat.thresholdMat;
	omxMatrix *weights = obsStat.acovMat;
	std::vector< omxThresholdColumn > &oThresh = obsStat.thresholdCols;

	numOrdinal = oo->expectation->numOrdinal;
	auto &eThresh = oo->expectation->getThresholdInfo();

	// Error Checking: Observed/Expected means must agree.
	// ^ is XOR: true when one is false and the other is not.
	if((newObj->expectedMeans == NULL) ^ (means == NULL)) {
		if(newObj->expectedMeans != NULL) {
			if (eThresh.size() == 0) {
				omxRaiseError("Observed means not detected, but expected means specified.\n"
					      "The model has no continuous variables. "
					      "Do you did forget allContinuousMethod='marginals'?");
			} else {
				omxRaiseError("Means are required when the data include ordinal measurements");
			}
			return;
		} else {
			omxRaiseError("Observed means were provided, but an expected means matrix was not specified.\n  If you provide observed means, you must specify a model for the means.\n");
			return;
		}
	}

	if((eThresh.size()==0) ^ (obsThresholdsMat==0)) {
		if (eThresh.size()) {
			omxRaiseError("Observed thresholds not detected, but an expected thresholds matrix was specified.\n   If you wish to model the thresholds, you must provide observed thresholds.\n ");
			return;
		} else {
			omxRaiseError("Observed thresholds were provided, but an expected thresholds matrix was not specified.\nIf you provide observed thresholds, you must specify a model for the thresholds.\n");
			return;
		}
	}

	if (obsThresholdsMat) {
		for(int i = 0; i < int(oThresh.size()); i++) {
			eThresh[i].numThresholds = oThresh[i].numThresholds;
		}
	}

	if (OMX_DEBUG) {
		mxLog("expected thresholds:");
		for (auto &th : eThresh) { th.log(); }
		mxLog("observed thresholds:");
		for (auto &th : oThresh) { th.log(); }
	}

	if(weights) {
		if (weights->rows != weights->cols || weights->cols != vectorSize) {
			omxRaiseErrorf("Developer Error in WLS-based FitFunction object: WLS-based expectation specified an incorrectly-sized weight matrix (%d != %d).\nIf you are not developing a new expectation type, you should probably post this to the OpenMx forums.", vectorSize, weights->cols);
			return;
		}

		EigenMatrixAdaptor Eweight(weights);
		Eigen::MatrixXd offDiagW = Eweight.triangularView<Eigen::StrictlyUpper>();
		double offDiag = offDiagW.array().abs().sum();
		oo->units = offDiag > 0.0? FIT_UNITS_SQUARED_RESIDUAL_CHISQ : FIT_UNITS_SQUARED_RESIDUAL;
	} else {
		oo->units = FIT_UNITS_SQUARED_RESIDUAL;
	}

	if (obsThresholdsMat && oo->expectation->thresholdsMat) {
		if (obsThresholdsMat->rows != oo->expectation->thresholdsMat->rows ||
		    obsThresholdsMat->cols != oo->expectation->thresholdsMat->cols) {
			omxRaiseError("Observed and expected threshold matrices must have the same number of rows and columns");
		}
	}

	observedFlattened = omxInitMatrix(vectorSize, 1, TRUE, matrix->currentState);
	flattenDataToVector(cov, means, obsStat.slopeMat, obsThresholdsMat,
			    oThresh, observedFlattened);
	if(OMX_DEBUG) {omxPrintMatrix(observedFlattened, "....WLS Observed Vector: "); }
	flattenDataToVector(newObj->expectedCov, newObj->expectedMeans,
			    newObj->expectedSlope, oo->expectation->thresholdsMat,
				eThresh, newObj->expectedFlattened);
}

void omxWLSFitFunction::init()
{
	auto *oo = this;

	omxState *currentState = oo->matrix->currentState;

	if (!oo->expectation) { mxThrow("%s requires an expectation", name()); }

	if (R_has_slot(rObj, Rf_install("type"))) {
		ProtectedSEXP RwlsType(R_do_slot(rObj, Rf_install("type")));
		type = CHAR(STRING_ELT(RwlsType,0));
	}
	if (R_has_slot(rObj, Rf_install("continuousType"))) {
		ProtectedSEXP RwlsContType(R_do_slot(rObj, Rf_install("continuousType")));
		continuousType = CHAR(STRING_ELT(RwlsContType,0));
	}
	if (R_has_slot(rObj, Rf_install("fullWeight"))) {
		ProtectedSEXP RwlsFullWeight(R_do_slot(rObj, Rf_install("fullWeight")));
		fullWeight = Rf_asLogical(RwlsFullWeight);
	}

	if (!fullWeight && !strEQ(type, "ULS")) {
		mxThrow("%s: !fullWeight && !strEQ(type, ULS)", name());
	}

	expectedCov = omxGetExpectationComponent(oo->expectation, "cov");
	expectedMeans = omxGetExpectationComponent(oo->expectation, "means");
	expectedSlope = omxGetExpectationComponent(expectation, "slope");

	/* Error check weight matrix size */
	vectorSize = expectation->numSummaryStats();
	if(OMX_DEBUG) { mxLog("Intial WLSFitFunction vectorSize comes to: %d.", vectorSize); }

	/* Temporary storage for calculation */
	observedFlattened = 0;
	expectedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	P = omxInitMatrix(1, vectorSize, TRUE, currentState);
	B = omxInitMatrix(vectorSize, 1, TRUE, currentState);
}
<commit_msg>better error for all continuous WLS with means, but != marginals<commit_after> /*
 *  Copyright 2007-2019 by the individuals mentioned in the source code history
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "omxData.h"
#include <Eigen/Core>
// #include <Eigen/Dense>
#include "EnableWarnings.h"

struct omxWLSFitFunction : omxFitFunction {

	omxMatrix* expectedCov;
	omxMatrix* expectedMeans;
	omxMatrix* expectedSlope;
	omxMatrix* observedFlattened;
	omxMatrix* expectedFlattened;
	omxMatrix* P;
	omxMatrix* B;
	int numOrdinal;
	int vectorSize;

	const char *type;
	const char *continuousType;
	bool fullWeight;

	omxWLSFitFunction() :
		type("WLS"), continuousType("cumulants"), fullWeight(true) {};
	virtual ~omxWLSFitFunction();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);

	void flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *slope, omxMatrix *thresholdMat,
				 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector);
	void prepData();
	virtual void invalidateCache()
	{
		omxFreeMatrix(observedFlattened);
		observedFlattened = 0;
	}
};

void omxWLSFitFunction::flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *slope,
					    omxMatrix *thresholdMat,
			 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector)
{
	EigenVectorAdaptor vec1(vector);
	normalToStdVector(cov, means, slope, thresholdMat, numOrdinal, thresholds, vec1);
}

omxWLSFitFunction::~omxWLSFitFunction()
{
	if(OMX_DEBUG) {mxLog("Freeing WLS FitFunction.");}

	invalidateCache();
	omxWLSFitFunction* owo = this;
	omxFreeMatrix(owo->expectedFlattened);
	omxFreeMatrix(owo->B);
	omxFreeMatrix(owo->P);
}

void omxWLSFitFunction::compute(int want, FitContext *fc)
{
	auto *oo = this;
	auto *owo = this;
	if (want & FF_COMPUTE_INITIAL_FIT) return;
	if ((want & FF_COMPUTE_PREOPTIMIZE) && !observedFlattened) {
		prepData();
		return;
	}

	if(OMX_DEBUG) { mxLog("Beginning WLS Evaluation.");}
	// Requires: Data, means, covariances.

	double sum = 0.0;

	omxMatrix *eCov, *eMeans, *oFlat, *eFlat;

	/* Locals for readability.  Compiler should cut through this. */
	eCov		= owo->expectedCov;
	eMeans 		= owo->expectedMeans;
	auto &eThresh   = oo->expectation->getThresholdInfo();
	if (!observedFlattened) return;
	oFlat		= observedFlattened;
	eFlat		= owo->expectedFlattened;
	int onei	= 1;

	/* Recompute and recopy */
	if(OMX_DEBUG) { mxLog("WLSFitFunction Computing expectation"); }
	omxExpectationCompute(fc, expectation, NULL);

	omxMatrix *expThresholdsMat = expectation->thresholdsMat;

	flattenDataToVector(eCov, eMeans, expectedSlope, expThresholdsMat, eThresh, eFlat);

	omxCopyMatrix(B, oFlat);

	if(OMX_DEBUG) {omxPrintMatrix(eFlat, "....WLS Expected Vector: "); }
	omxDAXPY(-1.0, eFlat, B);
	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed - Expected Vector: "); }

	omxMatrix *weights = expectation->data->getSingleObsSummaryStats().acovMat;
	if(weights != NULL) {
		//if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weights, "....WLS Weight Matrix: "); }
		omxDGEMV(TRUE, 1.0, weights, B, 0.0, P);
	} else {
		// ULS Case: Memcpy faster than dgemv.
		omxCopyMatrix(P, B);
		omxTransposeMatrix(P);
	}

	sum = F77_CALL(ddot)(&(P->cols), P->data, &onei, B->data, &onei);

	oo->matrix->data[0] = sum;

	if(OMX_DEBUG) { mxLog("WLSFitFunction value comes to: %f.", oo->matrix->data[0]); }

}

void omxWLSFitFunction::populateAttr(SEXP algebra)
{
	if(OMX_DEBUG) { mxLog("Populating WLS Attributes."); }

	omxWLSFitFunction *argStruct = this;
	omxMatrix *expCovInt = argStruct->expectedCov;	    		// Expected covariance
	omxMatrix *expMeanInt = argStruct->expectedMeans;			// Expected means
	omxMatrix *weightInt = expectation->data->getSingleObsSummaryStats().acovMat;

	SEXP expCovExt, expMeanExt, gradients;
	Rf_protect(expCovExt = Rf_allocMatrix(REALSXP, expCovInt->rows, expCovInt->cols));
	for(int row = 0; row < expCovInt->rows; row++)
		for(int col = 0; col < expCovInt->cols; col++)
			REAL(expCovExt)[col * expCovInt->rows + row] =
				omxMatrixElement(expCovInt, row, col);

	if (expMeanInt != NULL) {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, expMeanInt->rows, expMeanInt->cols));
		for(int row = 0; row < expMeanInt->rows; row++)
			for(int col = 0; col < expMeanInt->cols; col++)
				REAL(expMeanExt)[col * expMeanInt->rows + row] =
					omxMatrixElement(expMeanInt, row, col);
	} else {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weightInt, "...WLS Weight Matrix: W"); }
	SEXP weightExt = NULL;
	if (weightInt) {
		Rf_protect(weightExt = Rf_allocMatrix(REALSXP, weightInt->rows, weightInt->cols));
		for(int row = 0; row < weightInt->rows; row++)
			for(int col = 0; col < weightInt->cols; col++)
				REAL(weightExt)[col * weightInt->rows + row] = weightInt->data[col * weightInt->rows + row];
	}

	if(0) {  /* TODO fix for new internal API
		int nLocs = Global->numFreeParams;
		double gradient[Global->numFreeParams];
		for(int loc = 0; loc < nLocs; loc++) {
			gradient[loc] = NA_REAL;
		}
		//oo->gradientFun(oo, gradient);
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 1, nLocs));

		for(int loc = 0; loc < nLocs; loc++)
			REAL(gradients)[loc] = gradient[loc];
		 */
	} else {
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG) { mxLog("Installing populated WLS Attributes."); }
	Rf_setAttrib(algebra, Rf_install("expCov"), expCovExt);
	Rf_setAttrib(algebra, Rf_install("expMean"), expMeanExt);
	if (weightExt) Rf_setAttrib(algebra, Rf_install("weights"), weightExt);
	Rf_setAttrib(algebra, Rf_install("gradients"), gradients);

	ProtectedSEXP Rsat(Rf_ScalarReal(0));
	Rf_setAttrib(algebra, Rf_install("SaturatedLikelihood"), Rsat);
	//Rf_setAttrib(algebra, Rf_install("IndependenceLikelihood"), Rf_ScalarReal(0));
	ProtectedSEXP Rmisfit(Rf_ScalarReal(omxMatrixElement(matrix, 0, 0)));
	Rf_setAttrib(algebra, Rf_install("ADFMisfit"), Rmisfit);
}

omxFitFunction *omxInitWLSFitFunction()
{ return new omxWLSFitFunction; }

void omxWLSFitFunction::prepData()
{
	auto *oo = this;
	auto *newObj = this;

	if (vectorSize != expectation->numSummaryStats())
		mxThrow("%s: vectorSize changed from %d -> %d",
			name(), vectorSize, expectation->numSummaryStats());

	omxData* dataMat = oo->expectation->data;

	if (!matrix->currentState->isClone()) {
		std::vector<int> exoPred;
		expectation->getExogenousPredictors(exoPred);
		// how to prohibit def vars? TODO

		dataMat->prepObsStats(matrix->currentState, expectation->getDataColumnNames(),
				      exoPred, type, continuousType, fullWeight);
		if (isErrorRaised()) return;
	}

	auto &obsStat = dataMat->getSingleObsSummaryStats();
	//obsStat.log();
	omxMatrix *cov = obsStat.covMat;
	if (!cov) {
		omxRaiseErrorf("%s: an observed covariance matrix is required", name());
		return;
	}

	omxMatrix *means = obsStat.meansMat;
	omxMatrix *obsThresholdsMat = obsStat.thresholdMat;
	omxMatrix *weights = obsStat.acovMat;
	std::vector< omxThresholdColumn > &oThresh = obsStat.thresholdCols;

	numOrdinal = oo->expectation->numOrdinal;
	auto &eThresh = oo->expectation->getThresholdInfo();

	// Error Checking: Observed/Expected means must agree.
	// ^ is XOR: true when one is false and the other is not.
	if((newObj->expectedMeans == NULL) ^ (means == NULL)) {
		if(newObj->expectedMeans != NULL) {
			if (eThresh.size() == 0) {
				omxRaiseError("Observed means not detected, but expected means specified.\n"
				   "To model means with all continuous data, you need to set allContinuousMethod='marginals'");
			} else {
				omxRaiseError("Means are required when the data include ordinal measurements");
			}
			return;
		} else {
			omxRaiseError("Observed means were provided, but an expected means matrix was not specified.\n  If you provide observed means, you must specify a model for the means.\n");
			return;
		}
	}

	if((eThresh.size()==0) ^ (obsThresholdsMat==0)) {
		if (eThresh.size()) {
			omxRaiseError("Observed thresholds not detected, but an expected thresholds matrix was specified.\n   If you wish to model the thresholds, you must provide observed thresholds.\n ");
			return;
		} else {
			omxRaiseError("Observed thresholds were provided, but an expected thresholds matrix was not specified.\nIf you provide observed thresholds, you must specify a model for the thresholds.\n");
			return;
		}
	}

	if (obsThresholdsMat) {
		for(int i = 0; i < int(oThresh.size()); i++) {
			eThresh[i].numThresholds = oThresh[i].numThresholds;
		}
	}

	if (OMX_DEBUG) {
		mxLog("expected thresholds:");
		for (auto &th : eThresh) { th.log(); }
		mxLog("observed thresholds:");
		for (auto &th : oThresh) { th.log(); }
	}

	if(weights) {
		if (weights->rows != weights->cols || weights->cols != vectorSize) {
			omxRaiseErrorf("Developer Error in WLS-based FitFunction object: WLS-based expectation specified an incorrectly-sized weight matrix (%d != %d).\nIf you are not developing a new expectation type, you should probably post this to the OpenMx forums.", vectorSize, weights->cols);
			return;
		}

		EigenMatrixAdaptor Eweight(weights);
		Eigen::MatrixXd offDiagW = Eweight.triangularView<Eigen::StrictlyUpper>();
		double offDiag = offDiagW.array().abs().sum();
		oo->units = offDiag > 0.0? FIT_UNITS_SQUARED_RESIDUAL_CHISQ : FIT_UNITS_SQUARED_RESIDUAL;
	} else {
		oo->units = FIT_UNITS_SQUARED_RESIDUAL;
	}

	if (obsThresholdsMat && oo->expectation->thresholdsMat) {
		if (obsThresholdsMat->rows != oo->expectation->thresholdsMat->rows ||
		    obsThresholdsMat->cols != oo->expectation->thresholdsMat->cols) {
			omxRaiseError("Observed and expected threshold matrices must have the same number of rows and columns");
		}
	}

	observedFlattened = omxInitMatrix(vectorSize, 1, TRUE, matrix->currentState);
	flattenDataToVector(cov, means, obsStat.slopeMat, obsThresholdsMat,
			    oThresh, observedFlattened);
	if(OMX_DEBUG) {omxPrintMatrix(observedFlattened, "....WLS Observed Vector: "); }
	flattenDataToVector(newObj->expectedCov, newObj->expectedMeans,
			    newObj->expectedSlope, oo->expectation->thresholdsMat,
				eThresh, newObj->expectedFlattened);
}

void omxWLSFitFunction::init()
{
	auto *oo = this;

	omxState *currentState = oo->matrix->currentState;

	if (!oo->expectation) { mxThrow("%s requires an expectation", name()); }

	if (R_has_slot(rObj, Rf_install("type"))) {
		ProtectedSEXP RwlsType(R_do_slot(rObj, Rf_install("type")));
		type = CHAR(STRING_ELT(RwlsType,0));
	}
	if (R_has_slot(rObj, Rf_install("continuousType"))) {
		ProtectedSEXP RwlsContType(R_do_slot(rObj, Rf_install("continuousType")));
		continuousType = CHAR(STRING_ELT(RwlsContType,0));
	}
	if (R_has_slot(rObj, Rf_install("fullWeight"))) {
		ProtectedSEXP RwlsFullWeight(R_do_slot(rObj, Rf_install("fullWeight")));
		fullWeight = Rf_asLogical(RwlsFullWeight);
	}

	if (!fullWeight && !strEQ(type, "ULS")) {
		mxThrow("%s: !fullWeight && !strEQ(type, ULS)", name());
	}

	expectedCov = omxGetExpectationComponent(oo->expectation, "cov");
	expectedMeans = omxGetExpectationComponent(oo->expectation, "means");
	expectedSlope = omxGetExpectationComponent(expectation, "slope");

	/* Error check weight matrix size */
	vectorSize = expectation->numSummaryStats();
	if(OMX_DEBUG) { mxLog("Intial WLSFitFunction vectorSize comes to: %d.", vectorSize); }

	/* Temporary storage for calculation */
	observedFlattened = 0;
	expectedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	P = omxInitMatrix(1, vectorSize, TRUE, currentState);
	B = omxInitMatrix(vectorSize, 1, TRUE, currentState);
}
<|endoftext|>


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

// Convert a Perf profile to LLVM.

#include "config.h"

#if defined(HAVE_LLVM)
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "gflags/gflags.h"
#include "glog/logging.h"
#include "llvm_profile_writer.h"
#include "profile_writer.h"

DECLARE_bool(debug_dump);

namespace autofdo {

bool LLVMProfileBuilder::Write(const string &output_filename,
                               llvm::sampleprof::SampleProfileFormat format,
                               const SymbolMap &symbol_map,
                               const StringIndexMap &name_table) {
  // Collect the profiles for every symbol in the name table.
  LLVMProfileBuilder builder(name_table);
  const auto &profiles = builder.ConvertProfiles(symbol_map);

  // Write all the gathered profiles to the output file.
  auto WriterOrErr = llvm::sampleprof::SampleProfileWriter::create(
      llvm::StringRef(output_filename), format);
  if (std::error_code EC = WriterOrErr.getError()) {
    LOG(ERROR) << "Error creating profile output file '" << output_filename
               << "': " << EC.message();
    return false;
  }
  auto Writer = std::move(WriterOrErr.get());
  if (std::error_code EC = Writer->write(profiles)) {
    LOG(ERROR) << "Error writing profile output to '" << output_filename
               << "': " << EC.message();
    return false;
  }

  return true;
}

const llvm::StringMap<llvm::sampleprof::FunctionSamples>
    &LLVMProfileBuilder::ConvertProfiles(const SymbolMap &symbol_map) {
  Start(symbol_map);
  return GetProfiles();
}

void LLVMProfileBuilder::VisitTopSymbol(const string &name,
                                        const Symbol *node) {
  llvm::StringRef name_ref = GetNameRef(name);
  llvm::sampleprof::FunctionSamples &profile = profiles_[name_ref];
  if (std::error_code EC =
          llvm::MergeResult(result_, profile.addHeadSamples(node->head_count)))
    LOG(FATAL) << "Error updating head samples for '" << name
               << "': " << EC.message();

  if (std::error_code EC = llvm::MergeResult(
          result_, profile.addTotalSamples(node->total_count)))
    LOG(FATAL) << "Error updating total samples for '" << name
               << "': " << EC.message();

  profile.setName(name_ref);
  inline_stack_.clear();
  inline_stack_.push_back(&profile);
}

void LLVMProfileBuilder::VisitCallsite(const Callsite &callsite) {
  DCHECK_GE(inline_stack_.size(), 1);
  uint32 offset = callsite.first;
  uint32 line = offset >> 16;
  uint32 discriminator = offset & 0xffff;
  while (inline_stack_.size() > level_) {
    inline_stack_.pop_back();
  }
  auto &caller_profile = *(inline_stack_.back());
  auto CalleeName = GetNameRef(Symbol::Name(callsite.second));
  auto &callee_profile =
      caller_profile.functionSamplesAt(llvm::sampleprof::LineLocation(
          line, discriminator))[CalleeName];
  callee_profile.setName(CalleeName);
  inline_stack_.push_back(&callee_profile);
}

void LLVMProfileBuilder::Visit(const Symbol *node) {
  DCHECK_GE(inline_stack_.size(), 1);
  auto &profile = *(inline_stack_.back());

  if (level_ > 1) {
    // If this is a nested inline call, update its total count.
    if (std::error_code EC = llvm::MergeResult(
            result_, profile.addTotalSamples(node->total_count)))
      LOG(FATAL) << "Error updating total samples for '" << node->info.func_name
                 << "': " << EC.message();
  }

  // Emit all the locations and their sample counts.
  for (const auto &pos_count : node->pos_counts) {
    uint32 offset = pos_count.first;
    uint32 line = offset >> 16;
    uint32 discriminator = offset & 0xffff;
    const auto &num_samples = pos_count.second.count;
    if (std::error_code EC = llvm::MergeResult(
            result_, profile.addBodySamples(line, discriminator, num_samples)))
      LOG(FATAL) << "Error updating body samples for '" << node->info.func_name
                 << "': " << EC.message();

    // If there is a call at this location, emit the possible
    // targets. For direct calls, this will be the exact function
    // being invoked. For indirect calls, this will be a list of one
    // or more functions.
    const auto &target_map = pos_count.second.target_map;
    for (const auto &target_count : target_map) {
      if (std::error_code EC = llvm::MergeResult(
              result_, profile.addCalledTargetSamples(line, discriminator,
                                                      target_count.first,
                                                      target_count.second)))
        LOG(FATAL) << "Error updating called target samples for '"
                   << node->info.func_name << "': " << EC.message();
    }
  }
}

llvm::StringRef LLVMProfileBuilder::GetNameRef(const string &str) {
  StringIndexMap::const_iterator ret =
      name_table_.find(Symbol::Name(str.c_str()));
  CHECK(ret != name_table_.end());
  return llvm::StringRef(ret->first.c_str());
}

bool LLVMProfileWriter::WriteToFile(const string &output_filename) {
  if (FLAGS_debug_dump) Dump();

  // Populate the symbol table. This table contains all the symbols
  // for functions found in the binary.
  StringIndexMap name_table;
  StringTableUpdater::Update(*symbol_map_, &name_table);

  // Gather profiles for all the symbols.
  return LLVMProfileBuilder::Write(output_filename, format_, *symbol_map_,
                                   name_table);
}

}  // namespace autofdo

#endif  // HAVE_LLVM
<commit_msg>Fix build error for LLVM11<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Convert a Perf profile to LLVM.

#include "config.h"

#if defined(HAVE_LLVM)
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "gflags/gflags.h"
#include "glog/logging.h"
#include "llvm_profile_writer.h"
#include "profile_writer.h"

DECLARE_bool(debug_dump);

namespace autofdo {

bool LLVMProfileBuilder::Write(const string &output_filename,
                               llvm::sampleprof::SampleProfileFormat format,
                               const SymbolMap &symbol_map,
                               const StringIndexMap &name_table) {
  // Collect the profiles for every symbol in the name table.
  LLVMProfileBuilder builder(name_table);
  const auto &profiles = builder.ConvertProfiles(symbol_map);

  // Write all the gathered profiles to the output file.
  auto WriterOrErr = llvm::sampleprof::SampleProfileWriter::create(
      llvm::StringRef(output_filename), format);
  if (std::error_code EC = WriterOrErr.getError()) {
    LOG(ERROR) << "Error creating profile output file '" << output_filename
               << "': " << EC.message();
    return false;
  }
  auto Writer = std::move(WriterOrErr.get());
  if (std::error_code EC = Writer->write(profiles)) {
    LOG(ERROR) << "Error writing profile output to '" << output_filename
               << "': " << EC.message();
    return false;
  }

  return true;
}

const llvm::StringMap<llvm::sampleprof::FunctionSamples>
    &LLVMProfileBuilder::ConvertProfiles(const SymbolMap &symbol_map) {
  Start(symbol_map);
  return GetProfiles();
}

void LLVMProfileBuilder::VisitTopSymbol(const string &name,
                                        const Symbol *node) {
  llvm::StringRef name_ref = GetNameRef(name);
  llvm::sampleprof::FunctionSamples &profile = profiles_[name_ref];
  if (std::error_code EC =
          llvm::MergeResult(result_, profile.addHeadSamples(node->head_count)))
    LOG(FATAL) << "Error updating head samples for '" << name
               << "': " << EC.message();

  if (std::error_code EC = llvm::MergeResult(
          result_, profile.addTotalSamples(node->total_count)))
    LOG(FATAL) << "Error updating total samples for '" << name
               << "': " << EC.message();

  profile.setName(name_ref);
  inline_stack_.clear();
  inline_stack_.push_back(&profile);
}

void LLVMProfileBuilder::VisitCallsite(const Callsite &callsite) {
  DCHECK_GE(inline_stack_.size(), 1);
  uint32 offset = callsite.first;
  uint32 line = offset >> 16;
  uint32 discriminator = offset & 0xffff;
  while (inline_stack_.size() > level_) {
    inline_stack_.pop_back();
  }
  auto &caller_profile = *(inline_stack_.back());
  auto CalleeName =
    std::__cxx11::basic_string<char>(GetNameRef(Symbol::Name(callsite.second)).str());
  auto &callee_profile =
      caller_profile.functionSamplesAt(llvm::sampleprof::LineLocation(
          line, discriminator))[CalleeName];
  callee_profile.setName(CalleeName);
  inline_stack_.push_back(&callee_profile);
}

void LLVMProfileBuilder::Visit(const Symbol *node) {
  DCHECK_GE(inline_stack_.size(), 1);
  auto &profile = *(inline_stack_.back());

  if (level_ > 1) {
    // If this is a nested inline call, update its total count.
    if (std::error_code EC = llvm::MergeResult(
            result_, profile.addTotalSamples(node->total_count)))
      LOG(FATAL) << "Error updating total samples for '" << node->info.func_name
                 << "': " << EC.message();
  }

  // Emit all the locations and their sample counts.
  for (const auto &pos_count : node->pos_counts) {
    uint32 offset = pos_count.first;
    uint32 line = offset >> 16;
    uint32 discriminator = offset & 0xffff;
    const auto &num_samples = pos_count.second.count;
    if (std::error_code EC = llvm::MergeResult(
            result_, profile.addBodySamples(line, discriminator, num_samples)))
      LOG(FATAL) << "Error updating body samples for '" << node->info.func_name
                 << "': " << EC.message();

    // If there is a call at this location, emit the possible
    // targets. For direct calls, this will be the exact function
    // being invoked. For indirect calls, this will be a list of one
    // or more functions.
    const auto &target_map = pos_count.second.target_map;
    for (const auto &target_count : target_map) {
      if (std::error_code EC = llvm::MergeResult(
              result_, profile.addCalledTargetSamples(line, discriminator,
                                                      target_count.first,
                                                      target_count.second)))
        LOG(FATAL) << "Error updating called target samples for '"
                   << node->info.func_name << "': " << EC.message();
    }
  }
}

llvm::StringRef LLVMProfileBuilder::GetNameRef(const string &str) {
  StringIndexMap::const_iterator ret =
      name_table_.find(Symbol::Name(str.c_str()));
  CHECK(ret != name_table_.end());
  return llvm::StringRef(ret->first.c_str());
}

bool LLVMProfileWriter::WriteToFile(const string &output_filename) {
  if (FLAGS_debug_dump) Dump();

  // Populate the symbol table. This table contains all the symbols
  // for functions found in the binary.
  StringIndexMap name_table;
  StringTableUpdater::Update(*symbol_map_, &name_table);

  // Gather profiles for all the symbols.
  return LLVMProfileBuilder::Write(output_filename, format_, *symbol_map_,
                                   name_table);
}

}  // namespace autofdo

#endif  // HAVE_LLVM
<|endoftext|>


<commit_before>// This sample shows how to use a ci::gl::Fbo with multiple color attachments.
// It renders a spinning cube into two color attachments, one green and one blue.
// See multipleOut.frag for how to output frag colors in the shader.

#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Camera.h"
#include "cinder/Log.h"

using namespace ci;
using namespace ci::app;

class FboMultipleRenderTargetsApp : public App {
  public:
	virtual void	setup() override;
	virtual void	update() override;
	virtual void	draw() override;

  private:
	void			renderSceneToFbo();

	gl::FboRef			mFbo;
	gl::Texture2dRef	mTexAttachment0, mTexAttachment1;
	gl::GlslProgRef		mGlslMultipleOuts;
	mat4				mRotation;
	static const int	FBO_WIDTH = 256, FBO_HEIGHT = 256;
};

void FboMultipleRenderTargetsApp::setup()
{
	mTexAttachment0 = gl::Texture2d::create( FBO_WIDTH, FBO_HEIGHT );
	mTexAttachment1 = gl::Texture2d::create( FBO_WIDTH, FBO_HEIGHT );
	auto format = gl::Fbo::Format()
//			.samples( 4 ) // uncomment this to enable 4x antialiasing // FIXME: causes drawing to be all white
			.attachment( GL_COLOR_ATTACHMENT0, mTexAttachment0 )
			.attachment( GL_COLOR_ATTACHMENT1, mTexAttachment1 );
	mFbo = gl::Fbo::create( FBO_WIDTH, FBO_HEIGHT, format );

	try {
		mGlslMultipleOuts = gl::GlslProg::create( loadAsset( "multipleOut.vert" ), loadAsset( "multipleOut.frag" ) );
	}
	catch( Exception &exc ) {
		CI_LOG_EXCEPTION( "failed to load shader", exc );
	}

	gl::enableDepthRead();
	gl::enableDepthWrite();

	mRotation = mat4( 1 );
}

// Render our scene into the FBO (a cube)
void FboMultipleRenderTargetsApp::renderSceneToFbo()
{
	// setup our camera to render our scene
	CameraPersp cam( mFbo->getWidth(), mFbo->getHeight(), 60 );
	cam.setPerspective( 60, mFbo->getAspectRatio(), 1, 1000 );
	cam.lookAt( vec3( 2.8f, 1.8f, -2.8f ), vec3( 0 ) );

	// bind our framebuffer in a safe way:
	gl::ScopedFramebuffer fboScope( mFbo );

	// clear out both of the attachments of the FBO with black
	gl::clear();

	// setup the viewport to match the dimensions of the FBO, storing the previous state
	gl::ScopedViewport viewportScope( ivec2( 0 ), mFbo->getSize() );

	// store matrices before updating for CameraPersp
	gl::ScopedMatrices matScope;
	gl::setMatrices( cam );

	// set the modelview matrix to reflect our current rotation
	gl::multModelMatrix( mRotation );

	// render the torus with our multiple-output shader
	gl::ScopedGlslProg glslScope( mGlslMultipleOuts );
	gl::setDefaultShaderVars();
	gl::drawCube( vec3( 0 ), vec3( 2.2f ) );
}

void FboMultipleRenderTargetsApp::update()
{
	// Rotate the cube around an arbitrary axis
	mRotation *= rotate( 0.06f, normalize( vec3( 0.166f, 0.333f, 0.666f ) ) );

	// render into mFbo
	if( mFbo && mGlslMultipleOuts )
		renderSceneToFbo();
}

void FboMultipleRenderTargetsApp::draw()
{
	gl::clear( Color::gray( 0.35f ) );

	// draw the two textures we've created side-by-side
	gl::setMatricesWindow( getWindowSize() );
//	gl::draw( mFbo->getTexture(0), mFbo->getTexture(0)->getBounds() );
//	gl::draw( mFbo->getTexture(1), mFbo->getTexture(1)->getBounds() + vec2( mFbo->getTexture(0)->getWidth(), 0 ) );

	gl::draw( mTexAttachment0, mTexAttachment0->getBounds() );
	gl::draw( mTexAttachment1, mTexAttachment1->getBounds() + vec2( mTexAttachment0->getWidth(), 0 ) );
}

CINDER_APP( FboMultipleRenderTargetsApp, RendererGl )
<commit_msg>Updating FboMultipleRenderTargets to reflect recent changes<commit_after>// This sample shows how to use a ci::gl::Fbo with multiple color attachments.
// It renders a spinning cube into two color attachments, one green and one blue.
// See multipleOut.frag for how to output frag colors in the shader.

#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Camera.h"
#include "cinder/Log.h"

using namespace ci;
using namespace ci::app;

class FboMultipleRenderTargetsApp : public App {
  public:
	virtual void	setup() override;
	virtual void	update() override;
	virtual void	draw() override;

  private:
	void			renderSceneToFbo();

	gl::FboRef			mFbo;
	gl::GlslProgRef		mGlslMultipleOuts;
	mat4				mRotation;
	static const int	FBO_WIDTH = 256, FBO_HEIGHT = 256;
};

void FboMultipleRenderTargetsApp::setup()
{
	auto format = gl::Fbo::Format()
//			.samples( 4 ) // uncomment this to enable 4x antialiasing
			.attachment( GL_COLOR_ATTACHMENT0, gl::Texture2d::create( FBO_WIDTH, FBO_HEIGHT ) )
			.attachment( GL_COLOR_ATTACHMENT1, gl::Texture2d::create( FBO_WIDTH, FBO_HEIGHT ) );
	mFbo = gl::Fbo::create( FBO_WIDTH, FBO_HEIGHT, format );

	try {
		mGlslMultipleOuts = gl::GlslProg::create( loadAsset( "multipleOut.vert" ), loadAsset( "multipleOut.frag" ) );
	}
	catch( Exception &exc ) {
		CI_LOG_EXCEPTION( "failed to load shader", exc );
	}

	gl::enableDepthRead();
	gl::enableDepthWrite();

	mRotation = mat4( 1 );
}

// Render our scene into the FBO (a cube)
void FboMultipleRenderTargetsApp::renderSceneToFbo()
{
	// setup our camera to render our scene
	CameraPersp cam( mFbo->getWidth(), mFbo->getHeight(), 60 );
	cam.setPerspective( 60, mFbo->getAspectRatio(), 1, 1000 );
	cam.lookAt( vec3( 2.8f, 1.8f, -2.8f ), vec3( 0 ) );

	// bind our framebuffer in a safe way:
	gl::ScopedFramebuffer fboScope( mFbo );

	// clear out both of the attachments of the FBO with black
	gl::clear();

	// setup the viewport to match the dimensions of the FBO, storing the previous state
	gl::ScopedViewport viewportScope( ivec2( 0 ), mFbo->getSize() );

	// store matrices before updating for CameraPersp
	gl::ScopedMatrices matScope;
	gl::setMatrices( cam );

	// set the modelview matrix to reflect our current rotation
	gl::multModelMatrix( mRotation );

	// render the torus with our multiple-output shader
	gl::ScopedGlslProg glslScope( mGlslMultipleOuts );
	gl::drawCube( vec3( 0 ), vec3( 2.2f ) );
}

void FboMultipleRenderTargetsApp::update()
{
	// Rotate the cube around an arbitrary axis
	mRotation *= rotate( 0.06f, normalize( vec3( 0.166f, 0.333f, 0.666f ) ) );

	// render into mFbo
	if( mFbo && mGlslMultipleOuts )
		renderSceneToFbo();
}

void FboMultipleRenderTargetsApp::draw()
{
	gl::clear( Color::gray( 0.35f ) );

	gl::setMatricesWindow( getWindowSize() );

	// draw the two textures we've created side-by-side
	auto tex0 = mFbo->getTexture( GL_COLOR_ATTACHMENT0 );
	auto tex1 = mFbo->getTexture( GL_COLOR_ATTACHMENT1 );
	gl::draw( tex0, tex0->getBounds() );
	gl::draw( tex1, tex1->getBounds() + vec2( tex1->getWidth(), 0 ) );
}

CINDER_APP( FboMultipleRenderTargetsApp, RendererGl )
<|endoftext|>