<commit_before>/*
 */
#include "manifest.h"
#include "debug.h"
#include <vector>
#include <algorithm>
#include <sstream>  // stringstream
#include "helpers.h"    // path
#ifdef _WIN32
# include <Windows.h>
#else
# include <spawn.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <fcntl.h>
#endif

struct BuildList
{
    struct BuildEnt {
        const PackageManifest*  package;
        unsigned level;
    };
    ::std::vector<BuildEnt>  m_list;

    void add_dependencies(const PackageManifest& p, unsigned level);
    void add_package(const PackageManifest& p, unsigned level);
    void sort_list();

    struct Iter {
        const BuildList& l;
        size_t  i;

        const PackageManifest& operator*() const {
            return *this->l.m_list[this->l.m_list.size() - this->i - 1].package;
        }
        void operator++() {
            this->i++;
        }
        bool operator!=(const Iter& x) const {
            return this->i != x.i;
        }
        Iter begin() const {
            return *this;
        }
        Iter end() {
            return Iter{ this->l, this->l.m_list.size() };
        }
    };

    Iter iter() const {
        return Iter { *this, 0 };
    }
};

class Builder
{
    class StringList
    {
        ::std::vector<::std::string>    m_cached;
        ::std::vector<const char*>  m_strings;
    public:
        StringList()
        {
        }

        const ::std::vector<const char*>& get_vec() const
        {
            return m_strings;
        }

        void push_back(::std::string s)
        {
            m_cached.push_back(::std::move(s));
            m_strings.push_back(m_cached.back().c_str());
        }
        void push_back(const char* s)
        {
            m_strings.push_back(s);
        }
    };

public:
    bool build_target(const PackageManifest& manifest, const PackageTarget& target) const;
    bool build_library(const PackageManifest& manifest) const;

private:
    bool spawn_process(const StringList& args, const ::helpers::path& logfile) const;
};

void MiniCargo_Build(const PackageManifest& manifest)
{
    BuildList   list;

    list.add_dependencies(manifest, 0);

    list.sort_list();
    // dedup?
    for(const auto& p : list.iter())
    {
        DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path());
    }

    // Build dependencies
    Builder builder;
    for(const auto& p : list.iter())
    {
        if( ! builder.build_library(p) )
        {
            return;
        }
    }

    // TODO: If the manifest doesn't have a library, build the binary
    builder.build_library(manifest);
}

void BuildList::add_dependencies(const PackageManifest& p, unsigned level)
{
    for (const auto& dep : p.dependencies())
    {
        if( dep.is_optional() )
        {
            continue ;
        }
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::add_package(const PackageManifest& p, unsigned level)
{
    for(auto& ent : m_list)
    {
        if(ent.package == &p)
        {
            ent.level = level;
            return ;
        }
    }
    m_list.push_back({ &p, level });
    for (const auto& dep : p.dependencies())
    {
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::sort_list()
{
    ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level < b.level; });

    for(auto it = m_list.begin(); it != m_list.end(); )
    {
        auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; });
        if( it2 != it )
        {
            it = m_list.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const
{
    auto outdir = ::helpers::path("output");
    auto outfile = outdir / ::format("lib", target.m_name, ".hir");

    // TODO: Determine if it needs re-running
    // Rerun if:
    // > `outfile` is missing
    // > mrustc/minicargo is newer than `outfile`
    // > build script has changed
    // > any input file has changed (requires depfile from mrustc)

    StringList  args;
    args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));
    args.push_back("--crate-name"); args.push_back(target.m_name.c_str());
    args.push_back("--crate-type"); args.push_back("rlib");
    args.push_back("-o"); args.push_back(outfile);
    args.push_back("-L"); args.push_back(outdir);
    //for(const auto& dir : manifest.build_script.rustc_link_search) {
    //    args.push_back("-L"); args.push_back(dir.second.c_str());
    //}
    //for(const auto& lib : manifest.build_script.rustc_link_lib) {
    //    args.push_back("-l"); args.push_back(lib.second.c_str());
    //}
    //for(const auto& cfg : manifest.build_script.rustc_cfg) {
    //    args.push_back("--cfg"); args.push_back(cfg.c_str());
    //}
    //for(const auto& flag : manifest.build_script.rustc_flags) {
    //    args.push_back(flag.c_str());
    //}
    // TODO: Environment variables (rustc_env)

    return this->spawn_process(args, outfile + "_dbg.txt");
}
bool Builder::build_library(const PackageManifest& manifest) const
{
    if( manifest.build_script() != "" )
    {
        // Locate a build script override file
        // > Note, override file can specify a list of commands to run.
        //manifest.script_output = BuildScript::load( override_file );
        // Otherwise, compile and run build script
        //manifest.script_output = BuildScript::load( ::helpers::path("output") / "build_" + manifest.name + ".txt" );
        // Parse build script output.
        throw ::std::runtime_error("TODO: Build script");
    }

    return this->build_target(manifest, manifest.get_library());
}
bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfile) const
{
#ifdef _WIN32
    ::std::stringstream cmdline;
    cmdline << "mrustc.exe";
    for (const auto& arg : args.get_vec())
        cmdline << " " << arg;
    auto cmdline_str = cmdline.str();
    DEBUG("Calling " << cmdline_str);

    CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL);

    STARTUPINFO si = { 0 };
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    {
        SECURITY_ATTRIBUTES sa = { 0 };
        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        si.hStdOutput = CreateFile( static_cast<::std::string>(logfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        DWORD   tmp;
        WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL);
        WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL);
    }
    PROCESS_INFORMATION pi = { 0 };
    char env[] =
        "MRUSTC_DEBUG=""\0"
        ;
    CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    CloseHandle(si.hStdOutput);
    WaitForSingleObject(pi.hProcess, INFINITE);
    DWORD status = 1;
    GetExitCodeProcess(pi.hProcess, &status);
    if (status != 0)
    {
        DEBUG("Compiler exited with non-zero exit status " << status);
        return false;
    }
#else

    // Create logfile output directory
    mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755);

    // Create handles such that the log file is on stdout
    ::std::string logfile_str = logfile;
    pid_t pid;
    posix_spawn_file_actions_t  fa;
    {
        posix_spawn_file_actions_init(&fa);
        posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644);
    }

    // Generate `argv`
    auto argv = args.get_vec();
    argv.insert(argv.begin(), "mrustc");
    DEBUG("Calling " << argv);
    argv.push_back(nullptr);

    // Generate `envp`
    ::std::vector<const char*> envp;
    extern char **environ;
    for(auto p = environ; *p; p++)
    {
        envp.push_back(*p);
    }
    envp.push_back(nullptr);

    if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 )
    {
        perror("posix_spawn");
        DEBUG("Unable to spawn compiler");
        posix_spawn_file_actions_destroy(&fa);
        return false;
    }
    posix_spawn_file_actions_destroy(&fa);
    int status = -1;
    waitpid(pid, &status, 0);
    if( WEXITSTATUS(status) != 0 )
    {
        DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status));
        return false;
    }
#endif
    return true;
}
<commit_msg>minicargo - Fix build ordering<commit_after>/*
 */
#include "manifest.h"
#include "debug.h"
#include <vector>
#include <algorithm>
#include <sstream>  // stringstream
#include "helpers.h"    // path
#ifdef _WIN32
# include <Windows.h>
#else
# include <spawn.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <fcntl.h>
#endif

struct BuildList
{
    struct BuildEnt {
        const PackageManifest*  package;
        unsigned level;
    };
    ::std::vector<BuildEnt>  m_list;

    void add_dependencies(const PackageManifest& p, unsigned level);
    void add_package(const PackageManifest& p, unsigned level);
    void sort_list();

    struct Iter {
        const BuildList& l;
        size_t  i;

        const PackageManifest& operator*() const {
            return *this->l.m_list[this->i].package;
        }
        void operator++() {
            this->i++;
        }
        bool operator!=(const Iter& x) const {
            return this->i != x.i;
        }
        Iter begin() const {
            return *this;
        }
        Iter end() {
            return Iter{ this->l, this->l.m_list.size() };
        }
    };

    Iter iter() const {
        return Iter { *this, 0 };
    }
};

class Builder
{
    class StringList
    {
        ::std::vector<::std::string>    m_cached;
        ::std::vector<const char*>  m_strings;
    public:
        StringList()
        {
        }

        const ::std::vector<const char*>& get_vec() const
        {
            return m_strings;
        }

        void push_back(::std::string s)
        {
            m_cached.push_back(::std::move(s));
            m_strings.push_back(m_cached.back().c_str());
        }
        void push_back(const char* s)
        {
            m_strings.push_back(s);
        }
    };

public:
    bool build_target(const PackageManifest& manifest, const PackageTarget& target) const;
    bool build_library(const PackageManifest& manifest) const;

private:
    bool spawn_process(const StringList& args, const ::helpers::path& logfile) const;
};

void MiniCargo_Build(const PackageManifest& manifest)
{
    BuildList   list;

    list.add_dependencies(manifest, 0);

    list.sort_list();
    // dedup?
    for(const auto& p : list.iter())
    {
        DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path());
    }

    // Build dependencies
    Builder builder;
    for(const auto& p : list.iter())
    {
        if( ! builder.build_library(p) )
        {
            return;
        }
    }

    // TODO: If the manifest doesn't have a library, build the binary
    builder.build_library(manifest);
}

void BuildList::add_dependencies(const PackageManifest& p, unsigned level)
{
    for (const auto& dep : p.dependencies())
    {
        if( dep.is_optional() )
        {
            continue ;
        }
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::add_package(const PackageManifest& p, unsigned level)
{
    // If the package is already loaded
    for(auto& ent : m_list)
    {
        if(ent.package == &p && ent.level >= level)
        {
            // NOTE: Only skip if this package will be built before we needed (i.e. the level is greater)
            return ;
        }
        // Keep searching (might already have a higher entry)
    }
    m_list.push_back({ &p, level });
    for (const auto& dep : p.dependencies())
    {
        add_package(dep.get_package(), level+1);
    }
}
void BuildList::sort_list()
{
    ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level > b.level; });

    // Needed to deduplicate after sorting (`add_package` doesn't fully dedup)
    for(auto it = m_list.begin(); it != m_list.end(); )
    {
        auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; });
        if( it2 != it )
        {
            DEBUG((it2 - m_list.begin()) << ": Duplicate " << it->package->name() << " - Already at pos " << (it2 - m_list.begin()));
            it = m_list.erase(it);
        }
        else
        {
            DEBUG((it2 - m_list.begin()) << ": Keep " << it->package->name() << ", level = " << it->level);
            ++it;
        }
    }
}

bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const
{
    auto outdir = ::helpers::path("output");
    auto outfile = outdir / ::format("lib", target.m_name, ".hir");

    // TODO: Determine if it needs re-running
    // Rerun if:
    // > `outfile` is missing
    // > mrustc/minicargo is newer than `outfile`
    // > build script has changed
    // > any input file has changed (requires depfile from mrustc)

    StringList  args;
    args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));
    args.push_back("--crate-name"); args.push_back(target.m_name.c_str());
    args.push_back("--crate-type"); args.push_back("rlib");
    args.push_back("-o"); args.push_back(outfile);
    args.push_back("-L"); args.push_back(outdir);
    //for(const auto& dir : manifest.build_script.rustc_link_search) {
    //    args.push_back("-L"); args.push_back(dir.second.c_str());
    //}
    //for(const auto& lib : manifest.build_script.rustc_link_lib) {
    //    args.push_back("-l"); args.push_back(lib.second.c_str());
    //}
    //for(const auto& cfg : manifest.build_script.rustc_cfg) {
    //    args.push_back("--cfg"); args.push_back(cfg.c_str());
    //}
    //for(const auto& flag : manifest.build_script.rustc_flags) {
    //    args.push_back(flag.c_str());
    //}
    // TODO: Environment variables (rustc_env)

    return this->spawn_process(args, outfile + "_dbg.txt");
}
bool Builder::build_library(const PackageManifest& manifest) const
{
    if( manifest.build_script() != "" )
    {
        // Locate a build script override file
        // > Note, override file can specify a list of commands to run.
        //manifest.script_output = BuildScript::load( override_file );
        // Otherwise, compile and run build script
        //manifest.script_output = BuildScript::load( ::helpers::path("output") / "build_" + manifest.name + ".txt" );
        // Parse build script output.
        throw ::std::runtime_error("TODO: Build script for " + manifest.name());
    }

    return this->build_target(manifest, manifest.get_library());
}
bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfile) const
{
#ifdef _WIN32
    ::std::stringstream cmdline;
    cmdline << "mrustc.exe";
    for (const auto& arg : args.get_vec())
        cmdline << " " << arg;
    auto cmdline_str = cmdline.str();
    DEBUG("Calling " << cmdline_str);

    CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL);

    STARTUPINFO si = { 0 };
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    {
        SECURITY_ATTRIBUTES sa = { 0 };
        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        si.hStdOutput = CreateFile( static_cast<::std::string>(logfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        DWORD   tmp;
        WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL);
        WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL);
    }
    PROCESS_INFORMATION pi = { 0 };
    char env[] =
        "MRUSTC_DEBUG=""\0"
        ;
    CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    CloseHandle(si.hStdOutput);
    WaitForSingleObject(pi.hProcess, INFINITE);
    DWORD status = 1;
    GetExitCodeProcess(pi.hProcess, &status);
    if (status != 0)
    {
        DEBUG("Compiler exited with non-zero exit status " << status);
        return false;
    }
#else

    // Create logfile output directory
    mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755);

    // Create handles such that the log file is on stdout
    ::std::string logfile_str = logfile;
    pid_t pid;
    posix_spawn_file_actions_t  fa;
    {
        posix_spawn_file_actions_init(&fa);
        posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644);
    }

    // Generate `argv`
    auto argv = args.get_vec();
    argv.insert(argv.begin(), "mrustc");
    DEBUG("Calling " << argv);
    argv.push_back(nullptr);

    // Generate `envp`
    ::std::vector<const char*> envp;
    extern char **environ;
    for(auto p = environ; *p; p++)
    {
        envp.push_back(*p);
    }
    envp.push_back(nullptr);

    if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 )
    {
        perror("posix_spawn");
        DEBUG("Unable to spawn compiler");
        posix_spawn_file_actions_destroy(&fa);
        return false;
    }
    posix_spawn_file_actions_destroy(&fa);
    int status = -1;
    waitpid(pid, &status, 0);
    if( WEXITSTATUS(status) != 0 )
    {
        DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status));
        return false;
    }
#endif
    return true;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/initservice/mboxRegs.H $                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef MBOXREGS_H_
#define MBOXREGS_H_

namespace INITSERVICE
{
namespace SPLESS
{
    const   uint32_t    MBOX_SCRATCH_REG1 =   0x00050038; //CFAM 2838
    const   uint32_t    MBOX_SCRATCH_REG2 =   0x00050039; //CFAM 2839
    const   uint32_t    MBOX_SCRATCH_REG3 =   0x0005003a; //CFAM 283A
    const   uint32_t    MBOX_SCRATCH_REG4 =   0x0005003b; //CFAM 283B
    const   uint32_t    MBOX_SCRATCH_REG5 =   0x0005003c; //CFAM 283C
    const   uint32_t    MBOX_SCRATCH_REG6 =   0x0005003d; //CFAM 283D
    const   uint32_t    MBOX_SCRATCH_REG7 =   0x0005003e; //CFAM 283E
    const   uint32_t    MBOX_SCRATCH_REG8 =   0x0005003f; //CFAM 283F

    enum
    {
        SCRATCH_1 =   0x0, //Location in array is reg num -1
        SCRATCH_2 =   0x1,
        SCRATCH_3 =   0x2,
        SCRATCH_4 =   0x3,
        SCRATCH_5 =   0x4,
        SCRATCH_6 =   0x5,
        SCRATCH_7 =   0x6,
        SCRATCH_8 =   0x7,
    };

    // Mailbox Scratch Register 3
    union MboxScratch3_t
    {
        uint32_t data32;
        struct
        {
            uint32_t istepMode       :1;   //0
            uint32_t goToRuntime     :1;   //1
            uint32_t isMpipl         :1;   //2
            uint32_t fspAttached     :1;   //3
            uint32_t sbeFFDC         :1;   //4
            uint32_t sbeInternalFFDC :1;   //5
            uint32_t reserved        :26;  //6:31
        } PACKED;
    };

    // Mailbox Scratch Register 4
    union MboxScratch4_t
    {
        uint32_t data32;
        struct
        {
            uint32_t bootFreqMult        :16;   //0:15
            uint32_t cpFilterBypass      :1;    //16
            uint32_t ssFilterBypass      :1;    //17
            uint32_t ioFilterBypass      :1;    //18
            uint32_t dpllBypass          :1;    //19
            uint32_t nestMemXoPcieBypass :1;    //20
            uint32_t reserved            :3;    //21:23
            uint32_t nestPllBucket       :8;    //24:31
        } PACKED;
    };

    // Mailbox Scratch Register 5
    union MboxScratch5_t
    {
        uint32_t data32;
        struct
        {
            uint32_t cacheContained      :1;    //0
            uint32_t initAllCores        :1;    //1
            uint32_t riskLevel           :1;    //2
            uint32_t noBLVectors         :1;    //3
            uint32_t mcSyncMode          :1;    //4
            uint32_t reserved            :7;    //5:11
            uint32_t clockPllMux         :20;   //12:31
        } PACKED;
    };

    // Mailbox Scratch Register 7
    union MboxScratch7_t
    {
        uint32_t data32;
        struct
        {
            uint32_t drtmPayloadAddrMb   :32;   //0
        } PACKED;
    };

    // Mailbox Scratch Register 8
    union MboxScratch8_t
    {
        uint32_t data32;
        struct
        {
            uint32_t validFwFunctionalEqEc    :1;  //0
            uint32_t validSbeI2cBusSpeed      :1;  //1
            uint32_t validFwMode              :1;  //2
            uint32_t validBootFreq            :1;  //3
            uint32_t validHwpControlFlags     :1;  //4
            uint32_t validMasterSlaveChipNode :1;  //5
            uint32_t validDrtmPayloadAddr     :1;  //6
            uint32_t validBytes               :1;  //7
            uint32_t reserved                 :24; //8:31
        } PACKED;
    };

};
};
#endif
<commit_msg>Clean up some mbox scratch reg documentation<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/usr/initservice/mboxRegs.H $                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef MBOXREGS_H_
#define MBOXREGS_H_

namespace INITSERVICE
{
namespace SPLESS
{
    const   uint32_t    MBOX_SCRATCH_REG1 =   0x00050038; //CFAM 2838
    const   uint32_t    MBOX_SCRATCH_REG2 =   0x00050039; //CFAM 2839
    const   uint32_t    MBOX_SCRATCH_REG3 =   0x0005003a; //CFAM 283A
    const   uint32_t    MBOX_SCRATCH_REG4 =   0x0005003b; //CFAM 283B
    const   uint32_t    MBOX_SCRATCH_REG5 =   0x0005003c; //CFAM 283C
    const   uint32_t    MBOX_SCRATCH_REG6 =   0x0005003d; //CFAM 283D
    const   uint32_t    MBOX_SCRATCH_REG7 =   0x0005003e; //CFAM 283E
    const   uint32_t    MBOX_SCRATCH_REG8 =   0x0005003f; //CFAM 283F

    enum
    {
        SCRATCH_1 =   0x0, //Location in array is reg num -1
        SCRATCH_2 =   0x1,
        SCRATCH_3 =   0x2,
        SCRATCH_4 =   0x3,
        SCRATCH_5 =   0x4,
        SCRATCH_6 =   0x5,
        SCRATCH_7 =   0x6,
        SCRATCH_8 =   0x7,
    };

    // Mailbox Scratch Register 1
    union MboxScratch1_t
    {
        uint32_t data32;
        struct
        {
            // bit=1 means part is NOT functional
            uint32_t eqGard          :8;   //0:7
            uint32_t ecGard          :24;  //8:31
        } PACKED;
        // NOTE: Used for debug tool communication during Hostboot IPL
    };

    // Mailbox Scratch Register 2
    union MboxScratch2_t
    {
        uint32_t data32;
        struct
        {
            uint32_t i2cRefClockDiv  :16;  //00:15
            uint32_t ndlMeshCtl      :4;   //16:19
            uint32_t reserved        :12;  //20:31
        } PACKED;
        // NOTE: Used for debug tool communication during Hostboot IPL
    };

    // Mailbox Scratch Register 3
    union MboxScratch3_t
    {
        uint32_t data32;
        struct
        {
            uint32_t istepMode       :1;   //0
            uint32_t goToRuntime     :1;   //1
            uint32_t isMpipl         :1;   //2
            uint32_t fspAttached     :1;   //3
            uint32_t reserved1       :1;   //4
            uint32_t sbeInternalFFDC :1;   //5
            uint32_t reserved2       :26;  //6:31
        } PACKED;
    };

    // Mailbox Scratch Register 4
    union MboxScratch4_t
    {
        uint32_t data32;
        struct
        {
            uint32_t bootFreqMult        :16;   //0:15
            uint32_t cpFilterBypass      :1;    //16
            uint32_t ssFilterBypass      :1;    //17
            uint32_t ioFilterBypass      :1;    //18
            uint32_t dpllBypass          :1;    //19
            uint32_t nestMemXoPcieBypass :1;    //20
            uint32_t obusHalfSpeed       :1;    //21
            uint32_t reserved            :2;    //22:23
            uint32_t nestPllBucket       :8;    //24:31
        } PACKED;
        // NOTE: Used for debug tooling (SPLessCmd) during Hostboot IPL
        // NOTE: Used for sbe comm during runtime
    };

    // Mailbox Scratch Register 5
    union MboxScratch5_t
    {
        uint32_t data32;
        struct
        {
            uint32_t cacheContained      :1;    //0
            uint32_t initAllCores        :1;    //1
            uint32_t riskLevel           :1;    //2
            uint32_t noBLVectors         :1;    //3
            uint32_t mcSyncMode          :1;    //4
            uint32_t slowPci             :1;    //5
            uint32_t reserved            :6;    //6:11
            uint32_t clockPllMux         :20;   //12:31
        } PACKED;
    };

    // Mailbox Scratch Register 6
    union MboxScratch6_t
    {
        uint32_t data32;
        struct
        {
            uint32_t reserved1           :23;   //0:22
            uint32_t groupPumpMode       :1;    //23
            uint32_t isSlave             :1;    //24
            uint32_t reserved2           :1;    //25
            uint32_t groupId             :3;    //26:28
            uint32_t chipId              :3;    //29:31
        } PACKED;
    };

    // Mailbox Scratch Register 7
    union MboxScratch7_t
    {
        uint32_t data32;
        struct
        {
            uint32_t drtmPayloadAddrMb   :32;   //0
        } PACKED;
    };

    // Mailbox Scratch Register 8
    union MboxScratch8_t
    {
        uint32_t data32;
        struct
        {
            uint32_t validFwFunctionalEqEc    :1;  //0
            uint32_t validSbeI2cBusSpeed      :1;  //1
            uint32_t validFwMode              :1;  //2
            uint32_t validBootFreq            :1;  //3
            uint32_t validHwpControlFlags     :1;  //4
            uint32_t validMasterSlaveChipNode :1;  //5
            uint32_t validDrtmPayloadAddr     :1;  //6
            uint32_t validBytes               :1;  //7
            uint32_t reserved                 :24; //8:31
        } PACKED;
    };

};
};
#endif
<|endoftext|>


<commit_before>#include <GLFW/glfw3.h>

#include "../bench/util.hpp"
#include <mapbox/geojson.hpp>
#include <mapbox/geojsonvt.hpp>

using namespace mapbox::geojsonvt;

template <typename T>
void drawLine(const T points) {
    glColor4f(1, 0, 0, 1);
    glBegin(GL_LINE_STRIP);
    for (const auto& pt : points) {
        glVertex2s(pt.x, pt.y);
    }
    glEnd();
}

struct DrawFeature {
    void operator()(const mapbox::geometry::point<int16_t>&) {
    }

    void operator()(const mapbox::geometry::line_string<int16_t>& points) {
        drawLine(points);
    }

    void operator()(const mapbox::geometry::linear_ring<int16_t>& points) {
        drawLine(points);
    }

    void operator()(const mapbox::geometry::geometry<int16_t>& geometry) {
        mapbox::geometry::geometry<int16_t>::visit(geometry, DrawFeature{});
    }

    template <class T>
    void operator()(const T& vector) {
        for (const auto& e : vector) {
            operator()(e);
        }
    }
};

int main() {
    if (glfwInit() == 0) {
        return -1;
    }

    static int width = 768;
    static int fbWidth = width;
    static int height = 768;
    static int fbHeight = height;

    GLFWwindow* window =
        glfwCreateWindow(width, height, "GeoJSON VT — Drop a GeoJSON file", nullptr, nullptr);
    if (window == nullptr) {
        glfwTerminate();
        return -1;
    }

    static std::unique_ptr<GeoJSONVT> vt;

    static bool dirty = true;
    static struct TileID {
        int z;
        int x;
        int y;
    } pos = { 0, 0, 0 };

    enum class Horizontal { Left, Right, Outside };
    enum class Vertical { Top, Bottom, Outside };

    static Horizontal horizontal = Horizontal::Outside;
    static Vertical vertical = Vertical::Outside;

    Tile* tile = nullptr;

    static const auto updateTile = [&] {
        const std::string name =
            std::to_string(pos.z) + "/" + std::to_string(pos.x) + "/" + std::to_string(pos.y);
        if (vt) {
            Timer tileTimer;
            tile = const_cast<Tile*>(&vt->getTile(pos.z, pos.x, pos.y));
            tileTimer("tile " + name);
            glfwSetWindowTitle(window, (std::string{ "GeoJSON VT — " } + name).c_str());
        }
        dirty = true;
    };

    static const auto loadGeoJSON = [&](const std::string& filename) {
        Timer timer;
        const std::string data = loadFile(filename);
        timer("loadFile");

        const auto features =
            mapbox::geojson::parse(data).get<mapbox::geojson::feature_collection>();
        timer("parse into geometry");

        vt = std::make_unique<GeoJSONVT>(features);
        timer("generate tile index");
        updateTile();
    };

    static const auto updateLocation = [](const Horizontal newHorizontal,
                                          const Vertical newVertical) {
        if (newHorizontal != horizontal || newVertical != vertical) {
            dirty = true;
            horizontal = newHorizontal;
            vertical = newVertical;
        }
    };

    glfwSetDropCallback(window, [](GLFWwindow*, int count, const char* name[]) {
        if (count >= 1) {
            loadGeoJSON(name[0]);
        }
    });

    glfwSetKeyCallback(
        window, [](GLFWwindow* w, const int key, const int, const int action, const int) {
            if (key == GLFW_KEY_Q && action == GLFW_RELEASE) {
                glfwSetWindowShouldClose(w, 1);
            }
            if ((key == GLFW_KEY_BACKSPACE || key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
                // zoom out
                if (pos.z > 0) {
                    pos.z--;
                    pos.x /= 2;
                    pos.y /= 2;
                    updateTile();
                }
            }
        });

    glfwSetWindowSizeCallback(window, [](GLFWwindow*, const int w, const int h) {
        width = w;
        height = h;
        dirty = true;
    });

    glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, const int w, const int h) {
        fbWidth = w;
        fbHeight = h;
    });

    glfwSetCursorPosCallback(window, [](GLFWwindow*, const double x, const double y) {
        updateLocation((x > 0 && x < width) ? (x * 2 < width ? Horizontal::Left : Horizontal::Right)
                                            : Horizontal::Outside,
                       (y > 0 && y < height) ? (y * 2 < height ? Vertical::Top : Vertical::Bottom)
                                             : Vertical::Outside);
    });

    glfwSetCursorEnterCallback(window, [](GLFWwindow*, int entered) {
        if (entered == 0) {
            updateLocation(Horizontal::Outside, Vertical::Outside);
        }
    });

    glfwSetMouseButtonCallback(window, [](GLFWwindow*, int button, int action, int) {
        if (button == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) {
            // zoom into a particular tile
            if (pos.z < 18 && horizontal != Horizontal::Outside && vertical != Vertical::Outside) {
                pos.z++;
                pos.x *= 2;
                pos.y *= 2;
                if (horizontal == Horizontal::Right) {
                    pos.x++;
                }
                if (vertical == Vertical::Bottom) {
                    pos.y++;
                }
                updateTile();
            }
        } else if (button == GLFW_MOUSE_BUTTON_2 && action == GLFW_RELEASE) {
            // zoom out
            if (pos.z > 0) {
                pos.z--;
                pos.x /= 2;
                pos.y /= 2;
                updateTile();
            }
        }
    });

    glfwGetFramebufferSize(window, &fbWidth, &fbHeight);

    glfwMakeContextCurrent(window);

    const auto drawTile = [](bool active) {
        if (active) {
            glLineWidth(2);
            glColor4f(0, 0, 1, 1);
        } else {
            glLineWidth(1);
            glColor4f(0, 1, 0, 1);
        }

        glBegin(GL_LINE_STRIP);
        glVertex3f(0, 0, -static_cast<int>(active));
        glVertex3f(0, 4096, -static_cast<int>(active));
        glVertex3f(4096, 4096, -static_cast<int>(active));
        glVertex3f(4096, 0, -static_cast<int>(active));
        glVertex3f(0, 0, -static_cast<int>(active));
        glEnd();
    };

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_DEPTH_TEST);

    loadGeoJSON("data/countries.geojson");

    while (glfwWindowShouldClose(window) == 0) {
        if (dirty) {
            dirty = false;

            if (vt) {
                glClearColor(1, 1, 1, 1);
            } else {
                glClearColor(0.8, 0.8, 0.8, 1);
            }

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glViewport(0, 0, fbWidth, fbHeight);

            if (tile != nullptr) {
                // main tile
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-128, 4096 + 128, 4096 + 128, -128, 10, -10);

                glLineWidth(1);

                for (const auto& feature : tile->features) {
                    mapbox::geometry::geometry<int16_t>::visit(feature.geometry, DrawFeature{});
                }

                // top left
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-256, 8192 + 256, 8192 + 256, -256, 10, -10);
                drawTile(horizontal == Horizontal::Left && vertical == Vertical::Top);

                // top right
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-4096 - 256, 8192 + 256 - 4096, 8192 + 256, -256, 10, -10);
                drawTile(horizontal == Horizontal::Right && vertical == Vertical::Top);

                // bottom left
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-256, 8192 + 256, 8192 + 256 - 4096, -256 - 4096, 10, -10);
                drawTile(horizontal == Horizontal::Left && vertical == Vertical::Bottom);

                // bottom right
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-4096 - 256, 8192 + 256 - 4096, 8192 + 256 - 4096, -256 - 4096, 10, -10);
                drawTile(horizontal == Horizontal::Right && vertical == Vertical::Bottom);
            } else {
            }

            glfwSwapBuffers(window);
        }

        glfwWaitEvents();
    }

    glfwTerminate();
    return 0;
}
<commit_msg>Add missing include<commit_after>#include <GLFW/glfw3.h>
#include <memory>
#include "../bench/util.hpp"
#include <mapbox/geojson.hpp>
#include <mapbox/geojsonvt.hpp>

using namespace mapbox::geojsonvt;

template <typename T>
void drawLine(const T points) {
    glColor4f(1, 0, 0, 1);
    glBegin(GL_LINE_STRIP);
    for (const auto& pt : points) {
        glVertex2s(pt.x, pt.y);
    }
    glEnd();
}

struct DrawFeature {
    void operator()(const mapbox::geometry::point<int16_t>&) {
    }

    void operator()(const mapbox::geometry::line_string<int16_t>& points) {
        drawLine(points);
    }

    void operator()(const mapbox::geometry::linear_ring<int16_t>& points) {
        drawLine(points);
    }

    void operator()(const mapbox::geometry::geometry<int16_t>& geometry) {
        mapbox::geometry::geometry<int16_t>::visit(geometry, DrawFeature{});
    }

    template <class T>
    void operator()(const T& vector) {
        for (const auto& e : vector) {
            operator()(e);
        }
    }
};

int main() {
    if (glfwInit() == 0) {
        return -1;
    }

    static int width = 768;
    static int fbWidth = width;
    static int height = 768;
    static int fbHeight = height;

    GLFWwindow* window =
        glfwCreateWindow(width, height, "GeoJSON VT — Drop a GeoJSON file", nullptr, nullptr);
    if (window == nullptr) {
        glfwTerminate();
        return -1;
    }

    static std::unique_ptr<GeoJSONVT> vt;

    static bool dirty = true;
    static struct TileID {
        int z;
        int x;
        int y;
    } pos = { 0, 0, 0 };

    enum class Horizontal { Left, Right, Outside };
    enum class Vertical { Top, Bottom, Outside };

    static Horizontal horizontal = Horizontal::Outside;
    static Vertical vertical = Vertical::Outside;

    Tile* tile = nullptr;

    static const auto updateTile = [&] {
        const std::string name =
            std::to_string(pos.z) + "/" + std::to_string(pos.x) + "/" + std::to_string(pos.y);
        if (vt) {
            Timer tileTimer;
            tile = const_cast<Tile*>(&vt->getTile(pos.z, pos.x, pos.y));
            tileTimer("tile " + name);
            glfwSetWindowTitle(window, (std::string{ "GeoJSON VT — " } + name).c_str());
        }
        dirty = true;
    };

    static const auto loadGeoJSON = [&](const std::string& filename) {
        Timer timer;
        const std::string data = loadFile(filename);
        timer("loadFile");

        const auto features =
            mapbox::geojson::parse(data).get<mapbox::geojson::feature_collection>();
        timer("parse into geometry");

        vt = std::make_unique<GeoJSONVT>(features);
        timer("generate tile index");
        updateTile();
    };

    static const auto updateLocation = [](const Horizontal newHorizontal,
                                          const Vertical newVertical) {
        if (newHorizontal != horizontal || newVertical != vertical) {
            dirty = true;
            horizontal = newHorizontal;
            vertical = newVertical;
        }
    };

    glfwSetDropCallback(window, [](GLFWwindow*, int count, const char* name[]) {
        if (count >= 1) {
            loadGeoJSON(name[0]);
        }
    });

    glfwSetKeyCallback(
        window, [](GLFWwindow* w, const int key, const int, const int action, const int) {
            if (key == GLFW_KEY_Q && action == GLFW_RELEASE) {
                glfwSetWindowShouldClose(w, 1);
            }
            if ((key == GLFW_KEY_BACKSPACE || key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE) {
                // zoom out
                if (pos.z > 0) {
                    pos.z--;
                    pos.x /= 2;
                    pos.y /= 2;
                    updateTile();
                }
            }
        });

    glfwSetWindowSizeCallback(window, [](GLFWwindow*, const int w, const int h) {
        width = w;
        height = h;
        dirty = true;
    });

    glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, const int w, const int h) {
        fbWidth = w;
        fbHeight = h;
    });

    glfwSetCursorPosCallback(window, [](GLFWwindow*, const double x, const double y) {
        updateLocation((x > 0 && x < width) ? (x * 2 < width ? Horizontal::Left : Horizontal::Right)
                                            : Horizontal::Outside,
                       (y > 0 && y < height) ? (y * 2 < height ? Vertical::Top : Vertical::Bottom)
                                             : Vertical::Outside);
    });

    glfwSetCursorEnterCallback(window, [](GLFWwindow*, int entered) {
        if (entered == 0) {
            updateLocation(Horizontal::Outside, Vertical::Outside);
        }
    });

    glfwSetMouseButtonCallback(window, [](GLFWwindow*, int button, int action, int) {
        if (button == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) {
            // zoom into a particular tile
            if (pos.z < 18 && horizontal != Horizontal::Outside && vertical != Vertical::Outside) {
                pos.z++;
                pos.x *= 2;
                pos.y *= 2;
                if (horizontal == Horizontal::Right) {
                    pos.x++;
                }
                if (vertical == Vertical::Bottom) {
                    pos.y++;
                }
                updateTile();
            }
        } else if (button == GLFW_MOUSE_BUTTON_2 && action == GLFW_RELEASE) {
            // zoom out
            if (pos.z > 0) {
                pos.z--;
                pos.x /= 2;
                pos.y /= 2;
                updateTile();
            }
        }
    });

    glfwGetFramebufferSize(window, &fbWidth, &fbHeight);

    glfwMakeContextCurrent(window);

    const auto drawTile = [](bool active) {
        if (active) {
            glLineWidth(2);
            glColor4f(0, 0, 1, 1);
        } else {
            glLineWidth(1);
            glColor4f(0, 1, 0, 1);
        }

        glBegin(GL_LINE_STRIP);
        glVertex3f(0, 0, -static_cast<int>(active));
        glVertex3f(0, 4096, -static_cast<int>(active));
        glVertex3f(4096, 4096, -static_cast<int>(active));
        glVertex3f(4096, 0, -static_cast<int>(active));
        glVertex3f(0, 0, -static_cast<int>(active));
        glEnd();
    };

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_DEPTH_TEST);

    loadGeoJSON("data/countries.geojson");

    while (glfwWindowShouldClose(window) == 0) {
        if (dirty) {
            dirty = false;

            if (vt) {
                glClearColor(1, 1, 1, 1);
            } else {
                glClearColor(0.8, 0.8, 0.8, 1);
            }

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glViewport(0, 0, fbWidth, fbHeight);

            if (tile != nullptr) {
                // main tile
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-128, 4096 + 128, 4096 + 128, -128, 10, -10);

                glLineWidth(1);

                for (const auto& feature : tile->features) {
                    mapbox::geometry::geometry<int16_t>::visit(feature.geometry, DrawFeature{});
                }

                // top left
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-256, 8192 + 256, 8192 + 256, -256, 10, -10);
                drawTile(horizontal == Horizontal::Left && vertical == Vertical::Top);

                // top right
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-4096 - 256, 8192 + 256 - 4096, 8192 + 256, -256, 10, -10);
                drawTile(horizontal == Horizontal::Right && vertical == Vertical::Top);

                // bottom left
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-256, 8192 + 256, 8192 + 256 - 4096, -256 - 4096, 10, -10);
                drawTile(horizontal == Horizontal::Left && vertical == Vertical::Bottom);

                // bottom right
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glOrtho(-4096 - 256, 8192 + 256 - 4096, 8192 + 256 - 4096, -256 - 4096, 10, -10);
                drawTile(horizontal == Horizontal::Right && vertical == Vertical::Bottom);
            } else {
            }

            glfwSwapBuffers(window);
        }

        glfwWaitEvents();
    }

    glfwTerminate();
    return 0;
}
<|endoftext|>


<commit_before>#pragma once
/*
* Covariant Mozart Utility Library: Any
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2017 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.4.4
*/
#include "./base.hpp"
#include <functional>
#include <iostream>

namespace std {
	template<typename T> std::string to_string(const T&)
	{
		throw cov::error("E000D");
	}
	template<> std::string to_string<std::string>(const std::string& str)
	{
		return str;
	}
	template<> std::string to_string<bool>(const bool& v)
	{
		if(v)
			return "true";
		else
			return "false";
	}
}

namespace cov {
	template<typename _Tp> class compare_helper {
		template<typename T,typename X=bool>struct matcher;
		template<typename T> static constexpr bool match(T*)
		{
			return false;
		}
		template<typename T> static constexpr bool match(matcher < T, decltype(std::declval<T>()==std::declval<T>()) > *)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct compare_if;
	template<typename T>struct compare_if<T,true> {
		static bool compare(const T& a,const T& b)
		{
			return a==b;
		}
	};
	template<typename T>struct compare_if<T,false> {
		static bool compare(const T& a,const T& b)
		{
			return &a==&b;
		}
	};
	template<typename T>bool compare(const T& a,const T& b)
	{
		return compare_if<T,compare_helper<T>::value>::compare(a,b);
	}
	template<typename _Tp> class hash_helper {
		template<typename T,decltype(&std::hash<T>::operator()) X>struct matcher;
		template<typename T> static constexpr bool match(T*)
		{
			return false;
		}
		template<typename T> static constexpr bool match(matcher<T,&std::hash<T>::operator()>*)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct hash_if;
	template<typename T>struct hash_if<T,true> {
		static std::size_t hash(const T& val)
		{
			static std::hash<T> gen;
			return gen(val);
		}
	};
	template<typename T>struct hash_if<T,false> {
		static std::size_t hash(const T& val)
		{
			throw cov::error("E000F");
		}
	};
	template<typename T>std::size_t hash(const T& val)
	{
		return hash_if<T,hash_helper<T>::value>::hash(val);
	}
	template<typename T>void detach(T& val)
	{
		// Do something if you want when data is copying.
	}
	class any final {
		class baseHolder {
		public:
			baseHolder() = default;
			virtual ~ baseHolder() = default;
			virtual const std::type_info& type() const = 0;
			virtual baseHolder* duplicate() = 0;
			virtual bool compare(const baseHolder *) const = 0;
			virtual std::string to_string() const = 0;
			virtual std::size_t hash() const = 0;
			virtual void detach() = 0;
		};
		template < typename T > class holder:public baseHolder {
		protected:
			T mDat;
		public:
			holder() = default;
			template<typename...ArgsT>holder(ArgsT&&...args):mDat(std::forward<ArgsT>(args)...) {}
			virtual ~ holder() = default;
			virtual const std::type_info& type() const override
			{
				return typeid(T);
			}
			virtual baseHolder* duplicate() override
			{
				return new holder(mDat);
			}
			virtual bool compare(const baseHolder* obj) const override
			{
				if (obj->type()==this->type()) {
					const holder<T>* ptr=dynamic_cast<const holder<T>*>(obj);
					return ptr!=nullptr?cov::compare(mDat,ptr->data()):false;
				}
				return false;
			}
			virtual std::string to_string() const override
			{
				return std::to_string(mDat);
			}
			virtual std::size_t hash() const override
			{
				return cov::hash<T>(mDat);
			}
			virtual void detach() override
			{
				cov::detach(mDat);
			}
			T& data()
			{
				return mDat;
			}
			const T& data() const
			{
				return mDat;
			}
			void data(const T& dat)
			{
				mDat = dat;
			}
		};
		using size_t=unsigned long;
		struct proxy {
			size_t refcount=1;
			baseHolder* data=nullptr;
			proxy()=default;
			proxy(size_t rc,baseHolder* d):refcount(rc),data(d) {}
			~proxy()
			{
				delete data;
			}
		};
		proxy* mDat=nullptr;
		proxy* duplicate() const noexcept
		{
			if(mDat!=nullptr) {
				++mDat->refcount;
			}
			return mDat;
		}
		void recycle() noexcept
		{
			if(mDat!=nullptr) {
				--mDat->refcount;
				if(mDat->refcount==0) {
					delete mDat;
					mDat=nullptr;
				}
			}
		}
		any(proxy* dat):mDat(dat) {}
	public:
		void swap(any& obj,bool raw=false) noexcept
		{
			if(this->mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
				baseHolder* tmp=this->mDat->data;
				this->mDat->data=obj.mDat->data;
				obj.mDat->data=tmp;
			}
			else {
				proxy* tmp=this->mDat;
				this->mDat=obj.mDat;
				obj.mDat=tmp;
			}
		}
		void swap(any&& obj) noexcept
		{
			proxy* tmp=this->mDat;
			this->mDat=obj.mDat;
			obj.mDat=tmp;
		}
		void clone() noexcept
		{
			if(mDat!=nullptr) {
				proxy* dat=new proxy(1,mDat->data->duplicate());
				recycle();
				mDat=dat;
			}
		}
		bool usable() const noexcept
		{
			return mDat!=nullptr;
		}
		template<typename T,typename...ArgsT>static any make(ArgsT&&...args)
		{
			return any(new proxy(1,new holder<T>(std::forward<ArgsT>(args)...)));
		}
		any()=default;
		template<typename T> any(const T & dat):mDat(new proxy(1,new holder<T> (dat))) {}
		any(const any & v):mDat(v.duplicate()) {}
		any(any&& v) noexcept
		{
			swap(std::forward<any>(v));
		}
		~any()
		{
			recycle();
		}
		const std::type_info& type() const
		{
			return this->mDat!=nullptr?this->mDat->data->type():typeid(void);
		}
		std::string to_string() const
		{
			if(this->mDat==nullptr)
				return "Null";
			return this->mDat->data->to_string();
		}
		std::size_t hash() const
		{
			if(this->mDat==nullptr)
				return cov::hash<void*>(nullptr);
			return this->mDat->data->hash();
		}
		void detach()
		{
			if(this->mDat!=nullptr)
				this->mDat->data->detach();
		}
		bool is_same(const any& obj) const
		{
			return this->mDat==obj.mDat;
		}
		any& operator=(const any& var)
		{
			if(&var!=this) {
				recycle();
				mDat=var.duplicate();
			}
			return *this;
		}
		any& operator=(any&& var) noexcept
		{
			if(&var!=this)
				swap(std::forward<any>(var));
			return *this;
		}
		bool operator==(const any& var) const
		{
			return usable()?this->mDat->data->compare(var.mDat->data):!var.usable();
		}
		bool operator!=(const any& var)const
		{
			return usable()?!this->mDat->data->compare(var.mDat->data):var.usable();
		}
		template<typename T> T& val(bool raw=false)
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			if(!raw)
				clone();
			return dynamic_cast<holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> const T& val(bool raw=false) const
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			return dynamic_cast<const holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> const T& const_val() const
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			return dynamic_cast<const holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> operator const T&() const
		{
			return this->const_val<T>();
		}
		void assign(const any& obj,bool raw=false)
		{
			if(&obj!=this&&obj.mDat!=mDat) {
				if(mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
					delete mDat->data;
					mDat->data=obj.mDat->data->duplicate();
				}
				else {
					recycle();
					if(obj.mDat!=nullptr)
						mDat=new proxy(1,obj.mDat->data->duplicate());
					else
						mDat=nullptr;
				}
			}
		}
		template<typename T> void assign(const T& dat,bool raw=false)
		{
			if(raw) {
				delete mDat->data;
				mDat->data=new holder<T>(dat);
			}
			else {
				recycle();
				mDat=new proxy(1,new holder<T>(dat));
			}
		}
		template<typename T> any & operator=(const T& dat)
		{
			assign(dat);
			return *this;
		}
	};
	template<int N> class any::holder<char[N]>:public any::holder<std::string> {
	public:
		using holder<std::string>::holder;
	};
	template<> class any::holder<std::type_info>:public any::holder<std::type_index> {
	public:
		using holder<std::type_index>::holder;
	};
}

std::ostream& operator<<(std::ostream& out,const cov::any& val)
{
	out<<val.to_string();
	return out;
}

namespace std {
	template<> struct hash<cov::any> {
		std::size_t operator()(const cov::any& val) const
		{
			return val.hash();
		}
	};
}
<commit_msg>更新cov::any以适应covbasic的功能<commit_after>#pragma once
/*
* Covariant Mozart Utility Library: Any
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2017 Michael Lee(李登淳)
* Email: China-LDC@outlook.com
* Github: https://github.com/mikecovlee
* Website: http://ldc.atd3.cn
*
* Version: 17.4.4
*/
#include "./base.hpp"
#include <functional>
#include <iostream>

namespace std {
	template<typename T> std::string to_string(const T&)
	{
		throw cov::error("E000D");
	}
	template<> std::string to_string<std::string>(const std::string& str)
	{
		return str;
	}
	template<> std::string to_string<bool>(const bool& v)
	{
		if(v)
			return "true";
		else
			return "false";
	}
}

namespace cov {
	template<typename _Tp> class compare_helper {
		template<typename T,typename X=bool>struct matcher;
		template<typename T> static constexpr bool match(T*)
		{
			return false;
		}
		template<typename T> static constexpr bool match(matcher < T, decltype(std::declval<T>()==std::declval<T>()) > *)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct compare_if;
	template<typename T>struct compare_if<T,true> {
		static bool compare(const T& a,const T& b)
		{
			return a==b;
		}
	};
	template<typename T>struct compare_if<T,false> {
		static bool compare(const T& a,const T& b)
		{
			return &a==&b;
		}
	};
	template<typename T>bool compare(const T& a,const T& b)
	{
		return compare_if<T,compare_helper<T>::value>::compare(a,b);
	}
	template<typename _Tp> class hash_helper {
		template<typename T,decltype(&std::hash<T>::operator()) X>struct matcher;
		template<typename T> static constexpr bool match(T*)
		{
			return false;
		}
		template<typename T> static constexpr bool match(matcher<T,&std::hash<T>::operator()>*)
		{
			return true;
		}
	public:
		static constexpr bool value = match < _Tp > (nullptr);
	};
	template<typename,bool> struct hash_if;
	template<typename T>struct hash_if<T,true> {
		static std::size_t hash(const T& val)
		{
			static std::hash<T> gen;
			return gen(val);
		}
	};
	template<typename T>struct hash_if<T,false> {
		static std::size_t hash(const T& val)
		{
			throw cov::error("E000F");
		}
	};
	template<typename T>std::size_t hash(const T& val)
	{
		return hash_if<T,hash_helper<T>::value>::hash(val);
	}
	template<typename T>void detach(T& val)
	{
		// Do something if you want when data is copying.
	}
	class any final {
		class baseHolder {
		public:
			baseHolder() = default;
			virtual ~ baseHolder() = default;
			virtual const std::type_info& type() const = 0;
			virtual baseHolder* duplicate() = 0;
			virtual bool compare(const baseHolder *) const = 0;
			virtual std::string to_string() const = 0;
			virtual std::size_t hash() const = 0;
			virtual void detach() = 0;
		};
		template < typename T > class holder:public baseHolder {
		protected:
			T mDat;
		public:
			holder() = default;
			template<typename...ArgsT>holder(ArgsT&&...args):mDat(std::forward<ArgsT>(args)...) {}
			virtual ~ holder() = default;
			virtual const std::type_info& type() const override
			{
				return typeid(T);
			}
			virtual baseHolder* duplicate() override
			{
				return new holder(mDat);
			}
			virtual bool compare(const baseHolder* obj) const override
			{
				if (obj->type()==this->type()) {
					const holder<T>* ptr=dynamic_cast<const holder<T>*>(obj);
					return ptr!=nullptr?cov::compare(mDat,ptr->data()):false;
				}
				return false;
			}
			virtual std::string to_string() const override
			{
				return std::to_string(mDat);
			}
			virtual std::size_t hash() const override
			{
				return cov::hash<T>(mDat);
			}
			virtual void detach() override
			{
				cov::detach(mDat);
			}
			T& data()
			{
				return mDat;
			}
			const T& data() const
			{
				return mDat;
			}
			void data(const T& dat)
			{
				mDat = dat;
			}
		};
		using size_t=unsigned long;
		struct proxy {
			size_t refcount=1;
			baseHolder* data=nullptr;
			proxy()=default;
			proxy(size_t rc,baseHolder* d):refcount(rc),data(d) {}
			~proxy()
			{
				delete data;
			}
		};
		proxy* mDat=nullptr;
		proxy* duplicate() const noexcept
		{
			if(mDat!=nullptr) {
				++mDat->refcount;
			}
			return mDat;
		}
		void recycle() noexcept
		{
			if(mDat!=nullptr) {
				--mDat->refcount;
				if(mDat->refcount==0) {
					delete mDat;
					mDat=nullptr;
				}
			}
		}
		any(proxy* dat):mDat(dat) {}
	public:
		void swap(any& obj,bool raw=false) noexcept
		{
			if(this->mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
				baseHolder* tmp=this->mDat->data;
				this->mDat->data=obj.mDat->data;
				obj.mDat->data=tmp;
			}
			else {
				proxy* tmp=this->mDat;
				this->mDat=obj.mDat;
				obj.mDat=tmp;
			}
		}
		void swap(any&& obj,bool raw=false) noexcept
		{
			if(this->mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
				baseHolder* tmp=this->mDat->data;
				this->mDat->data=obj.mDat->data;
				obj.mDat->data=tmp;
			}
			else {
				proxy* tmp=this->mDat;
				this->mDat=obj.mDat;
				obj.mDat=tmp;
			}
		}
		void clone() noexcept
		{
			if(mDat!=nullptr) {
				proxy* dat=new proxy(1,mDat->data->duplicate());
				recycle();
				mDat=dat;
			}
		}
		bool usable() const noexcept
		{
			return mDat!=nullptr;
		}
		template<typename T,typename...ArgsT>static any make(ArgsT&&...args)
		{
			return any(new proxy(1,new holder<T>(std::forward<ArgsT>(args)...)));
		}
		any()=default;
		template<typename T> any(const T & dat):mDat(new proxy(1,new holder<T> (dat))) {}
		any(const any & v):mDat(v.duplicate()) {}
		any(any&& v) noexcept
		{
			swap(std::forward<any>(v));
		}
		~any()
		{
			recycle();
		}
		const std::type_info& type() const
		{
			return this->mDat!=nullptr?this->mDat->data->type():typeid(void);
		}
		std::string to_string() const
		{
			if(this->mDat==nullptr)
				return "Null";
			return this->mDat->data->to_string();
		}
		std::size_t hash() const
		{
			if(this->mDat==nullptr)
				return cov::hash<void*>(nullptr);
			return this->mDat->data->hash();
		}
		void detach()
		{
			if(this->mDat!=nullptr)
				this->mDat->data->detach();
		}
		bool is_same(const any& obj) const
		{
			return this->mDat==obj.mDat;
		}
		any& operator=(const any& var)
		{
			if(&var!=this) {
				recycle();
				mDat=var.duplicate();
			}
			return *this;
		}
		any& operator=(any&& var) noexcept
		{
			if(&var!=this)
				swap(std::forward<any>(var));
			return *this;
		}
		bool operator==(const any& var) const
		{
			return usable()?this->mDat->data->compare(var.mDat->data):!var.usable();
		}
		bool operator!=(const any& var)const
		{
			return usable()?!this->mDat->data->compare(var.mDat->data):var.usable();
		}
		template<typename T> T& val(bool raw=false)
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			if(!raw)
				clone();
			return dynamic_cast<holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> const T& val(bool raw=false) const
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			return dynamic_cast<const holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> const T& const_val() const
		{
			if(typeid(T)!=this->type())
				throw cov::error("E0006");
			if(this->mDat==nullptr)
				throw cov::error("E0005");
			return dynamic_cast<const holder<T>*>(this->mDat->data)->data();
		}
		template<typename T> operator const T&() const
		{
			return this->const_val<T>();
		}
		void assign(const any& obj,bool raw=false)
		{
			if(&obj!=this&&obj.mDat!=mDat) {
				if(mDat!=nullptr&&obj.mDat!=nullptr&&raw) {
					delete mDat->data;
					mDat->data=obj.mDat->data->duplicate();
				}
				else {
					recycle();
					if(obj.mDat!=nullptr)
						mDat=new proxy(1,obj.mDat->data->duplicate());
					else
						mDat=nullptr;
				}
			}
		}
		template<typename T> void assign(const T& dat,bool raw=false)
		{
			if(raw) {
				delete mDat->data;
				mDat->data=new holder<T>(dat);
			}
			else {
				recycle();
				mDat=new proxy(1,new holder<T>(dat));
			}
		}
		template<typename T> any & operator=(const T& dat)
		{
			assign(dat);
			return *this;
		}
	};
	template<int N> class any::holder<char[N]>:public any::holder<std::string> {
	public:
		using holder<std::string>::holder;
	};
	template<> class any::holder<std::type_info>:public any::holder<std::type_index> {
	public:
		using holder<std::type_index>::holder;
	};
}

std::ostream& operator<<(std::ostream& out,const cov::any& val)
{
	out<<val.to_string();
	return out;
}

namespace std {
	template<> struct hash<cov::any> {
		std::size_t operator()(const cov::any& val) const
		{
			return val.hash();
		}
	};
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LGPL.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

   Alternatively, this file is available under the Mozilla Public License
   Version 1.1.  You may obtain a copy of the License at
   http://www.mozilla.org/MPL/
*/

#include "localsocket.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "sys/uio.h"
#include <sys/un.h>
#include <unistd.h>

#include <cassert>
#include <climits>
#include <cstdlib>
#include <cstring>

// HACK, put this somewhere else (get the value from original d-bus? or is it infinite?)
static const int maxFds = 12;

using namespace std;

LocalSocket::LocalSocket(const string &socketFilePath)
   : m_fd(-1)
{
    m_supportsFileDescriptors = true;
    const int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        return;
    }
    // don't let forks inherit the file descriptor - that can cause confusion...
    fcntl(fd, F_SETFD, FD_CLOEXEC);

    struct sockaddr_un addr;
    addr.sun_family = PF_UNIX;
    bool ok = socketFilePath.length() < sizeof(addr.sun_path);
    if (ok) {
        memcpy(addr.sun_path, socketFilePath.c_str(), socketFilePath.length());
    }

    ok = ok && (connect(fd, (struct sockaddr *)&addr, sizeof(sa_family_t) + socketFilePath.length()) == 0);

    if (ok) {
        m_fd = fd;
    } else {
        ::close(fd);
    }
}

LocalSocket::LocalSocket(int fd)
   : m_fd(fd)
{
}

LocalSocket::~LocalSocket()
{
    close();
}

void LocalSocket::close()
{
    setEventDispatcher(nullptr);
    if (m_fd >= 0) {
        ::close(m_fd);
    }
    m_fd = -1;
}

uint32 LocalSocket::write(chunk data)
{
    if (m_fd < 0) {
        return 0; // TODO -1?
    }

    const uint32 initialLength = data.length;

    while (data.length > 0) {
        ssize_t nbytes = send(m_fd, data.ptr, data.length, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // see EAGAIN comment in read()
            if (errno == EAGAIN /* && iov.iov_len < a.length */ ) {
                break;
            }
            close();
            return false;
        }

        data.ptr += nbytes;
        data.length -= size_t(nbytes);
    }

    return initialLength - data.length;
}

// TODO: consider using iovec to avoid "copying together" message parts before sending; iovec tricks
// are probably not going to help for receiving, though.
uint32 LocalSocket::writeWithFileDescriptors(chunk data, const vector<int> &fileDescriptors)
{
    if (m_fd < 0) {
        return 0; // TODO -1?
    }

    // sendmsg  boilerplate
    struct msghdr send_msg;
    struct iovec iov;

    send_msg.msg_name = 0;
    send_msg.msg_namelen = 0;
    send_msg.msg_flags = 0;
    send_msg.msg_iov = &iov;
    send_msg.msg_iovlen = 1;

    iov.iov_base = data.ptr;
    iov.iov_len = data.length;

    // we can only send a fixed number of fds anyway due to the non-flexible size of the control message
    // receive buffer, so we set an arbitrary limit.
    const uint32 numFds = fileDescriptors.size();
    assert(fileDescriptors.size() <= maxFds); // TODO proper error

    char cmsgBuf[CMSG_SPACE(sizeof(int) * maxFds)];

    if (numFds) {
        // fill in a control message
        send_msg.msg_control = cmsgBuf;
        send_msg.msg_controllen = CMSG_SPACE(sizeof(int) * numFds);

        struct cmsghdr *c_msg = CMSG_FIRSTHDR(&send_msg);
        c_msg->cmsg_len = CMSG_LEN(sizeof(int) * numFds);
        c_msg->cmsg_level = SOL_SOCKET;
        c_msg->cmsg_type = SCM_RIGHTS;

        // set the control data to pass - this is why we don't use the simpler write()
        for (uint32 i = 0; i < numFds; i++) {
            reinterpret_cast<int *>(CMSG_DATA(c_msg))[i] = fileDescriptors[i];
        }
    } else {
        // no file descriptor to send, no control message
        send_msg.msg_control = 0;
        send_msg.msg_controllen = 0;
    }

    while (iov.iov_len > 0) {
        ssize_t nbytes = sendmsg(m_fd, &send_msg, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // see EAGAIN comment in read()
            if (errno == EAGAIN /* && iov.iov_len < a.length */ ) {
                break;
            }
            close();
            return false;
        }

        iov.iov_base = static_cast<char *>(iov.iov_base) + nbytes;
        iov.iov_len -= size_t(nbytes);
    }

    return data.length - iov.iov_len;
}

uint32 LocalSocket::availableBytesForReading()
{
    uint32 available = 0;
    if (ioctl(m_fd, FIONREAD, &available) < 0) {
        available = 0;
    }
    return available;
}

chunk LocalSocket::read(byte *buffer, uint32 maxSize)
{
    chunk ret(buffer, 0);

    while (ret.length < maxSize) {
        ssize_t nbytes = recv(m_fd, ret.ptr + ret.length, maxSize - ret.length, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // If we were notified for reading directly by the event dispatcher, we must be able to read at
            // least one byte before getting AGAIN aka EWOULDBLOCK - *however* the event loop might notify
            // something that is very eager to read everything (like Message::notifyRead()...) by reading
            // multiple times and in that case, we may be called in an attempt to read more when there is
            // currently no more data.
            // Just return zero bytes and no error in that case.
            if (errno == EAGAIN /* && iov.iov_len < maxSize */) {
                break;
            }
            close();
            return ret;
        }
        ret.length += size_t(nbytes);
    }

    return ret;
}

chunk LocalSocket::readWithFileDescriptors(byte *buffer, uint32 maxSize, vector<int> *fileDescriptors)
{
    chunk ret;
    if (maxSize <= 0) {
        return ret;
    }

    // recvmsg-with-control-message boilerplate
    struct msghdr recv_msg;
    char cmsgBuf[CMSG_SPACE(sizeof(int) * maxFds)];
    memset(cmsgBuf, 0, sizeof(cmsgBuf));

    recv_msg.msg_control = cmsgBuf;
    recv_msg.msg_controllen = sizeof(cmsgBuf);
    recv_msg.msg_name = 0;
    recv_msg.msg_namelen = 0;
    recv_msg.msg_flags = 0;

    struct iovec iov;
    recv_msg.msg_iov = &iov;
    recv_msg.msg_iovlen = 1;

    // end boilerplate

    ret.ptr = buffer;
    ret.length = 0;
    iov.iov_base = ret.ptr;
    iov.iov_len = maxSize;
    while (iov.iov_len > 0) {
        ssize_t nbytes = recvmsg(m_fd, &recv_msg, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // If we were notified for reading directly by the event dispatcher, we must be able to read at
            // least one byte before getting AGAIN aka EWOULDBLOCK - *however* the event loop might notify
            // something that is very eager to read everything (like Message::notifyRead()...) by reading
            // multiple times and in that case, we may be called in an attempt to read more when there is
            // currently no more data.
            // Just return zero bytes and no error in that case.
            if (errno == EAGAIN /* && iov.iov_len < maxSize */) {
                break;
            }
            close();
            return ret;
        }
        ret.length += size_t(nbytes);
        iov.iov_base = static_cast<char *>(iov.iov_base) + nbytes;
        iov.iov_len -= size_t(nbytes);
    }

    // done reading "regular data", now read any file descriptors passed via control messages

    struct cmsghdr *c_msg = CMSG_FIRSTHDR(&recv_msg);
    if (c_msg && c_msg->cmsg_level == SOL_SOCKET && c_msg->cmsg_type == SCM_RIGHTS) {
        const int len = c_msg->cmsg_len / sizeof(int);
        int *cmsgData = reinterpret_cast<int *>(CMSG_DATA(c_msg));
        for (int i = 0; i < len; i++) {
            fileDescriptors->push_back(cmsgData[i]);
        }
    }

    return ret;
}

bool LocalSocket::isOpen()
{
    return m_fd != -1;
}

int LocalSocket::fileDescriptor() const
{
    return m_fd;
}

void LocalSocket::handleCanRead()
{
    if (availableBytesForReading()) {
        ITransport::handleCanRead();
    } else {
        // This should really only happen in error cases! ### TODO test?
        close();
    }
}
<commit_msg>LocalSocket: take null-terminator of socket path into account<commit_after>/*
   Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LGPL.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

   Alternatively, this file is available under the Mozilla Public License
   Version 1.1.  You may obtain a copy of the License at
   http://www.mozilla.org/MPL/
*/

#include "localsocket.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "sys/uio.h"
#include <sys/un.h>
#include <unistd.h>

#include <cassert>
#include <climits>
#include <cstdlib>
#include <cstring>

// HACK, put this somewhere else (get the value from original d-bus? or is it infinite?)
static const int maxFds = 12;

using namespace std;

LocalSocket::LocalSocket(const string &socketFilePath)
   : m_fd(-1)
{
    m_supportsFileDescriptors = true;
    const int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        return;
    }
    // don't let forks inherit the file descriptor - that can cause confusion...
    fcntl(fd, F_SETFD, FD_CLOEXEC);

    struct sockaddr_un addr;
    addr.sun_family = PF_UNIX;
    bool ok = socketFilePath.length() < sizeof(addr.sun_path);
    if (ok) {
        memcpy(addr.sun_path, socketFilePath.c_str(), socketFilePath.length() + 1);
    }

    ok = ok && (connect(fd, (struct sockaddr *)&addr,
                        sizeof(sa_family_t) + socketFilePath.length() + 1) == 0);

    if (ok) {
        m_fd = fd;
    } else {
        ::close(fd);
    }
}

LocalSocket::LocalSocket(int fd)
   : m_fd(fd)
{
}

LocalSocket::~LocalSocket()
{
    close();
}

void LocalSocket::close()
{
    setEventDispatcher(nullptr);
    if (m_fd >= 0) {
        ::close(m_fd);
    }
    m_fd = -1;
}

uint32 LocalSocket::write(chunk data)
{
    if (m_fd < 0) {
        return 0; // TODO -1?
    }

    const uint32 initialLength = data.length;

    while (data.length > 0) {
        ssize_t nbytes = send(m_fd, data.ptr, data.length, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // see EAGAIN comment in read()
            if (errno == EAGAIN /* && iov.iov_len < a.length */ ) {
                break;
            }
            close();
            return false;
        }

        data.ptr += nbytes;
        data.length -= size_t(nbytes);
    }

    return initialLength - data.length;
}

// TODO: consider using iovec to avoid "copying together" message parts before sending; iovec tricks
// are probably not going to help for receiving, though.
uint32 LocalSocket::writeWithFileDescriptors(chunk data, const vector<int> &fileDescriptors)
{
    if (m_fd < 0) {
        return 0; // TODO -1?
    }

    // sendmsg  boilerplate
    struct msghdr send_msg;
    struct iovec iov;

    send_msg.msg_name = 0;
    send_msg.msg_namelen = 0;
    send_msg.msg_flags = 0;
    send_msg.msg_iov = &iov;
    send_msg.msg_iovlen = 1;

    iov.iov_base = data.ptr;
    iov.iov_len = data.length;

    // we can only send a fixed number of fds anyway due to the non-flexible size of the control message
    // receive buffer, so we set an arbitrary limit.
    const uint32 numFds = fileDescriptors.size();
    assert(fileDescriptors.size() <= maxFds); // TODO proper error

    char cmsgBuf[CMSG_SPACE(sizeof(int) * maxFds)];

    if (numFds) {
        // fill in a control message
        send_msg.msg_control = cmsgBuf;
        send_msg.msg_controllen = CMSG_SPACE(sizeof(int) * numFds);

        struct cmsghdr *c_msg = CMSG_FIRSTHDR(&send_msg);
        c_msg->cmsg_len = CMSG_LEN(sizeof(int) * numFds);
        c_msg->cmsg_level = SOL_SOCKET;
        c_msg->cmsg_type = SCM_RIGHTS;

        // set the control data to pass - this is why we don't use the simpler write()
        for (uint32 i = 0; i < numFds; i++) {
            reinterpret_cast<int *>(CMSG_DATA(c_msg))[i] = fileDescriptors[i];
        }
    } else {
        // no file descriptor to send, no control message
        send_msg.msg_control = 0;
        send_msg.msg_controllen = 0;
    }

    while (iov.iov_len > 0) {
        ssize_t nbytes = sendmsg(m_fd, &send_msg, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // see EAGAIN comment in read()
            if (errno == EAGAIN /* && iov.iov_len < a.length */ ) {
                break;
            }
            close();
            return false;
        }

        iov.iov_base = static_cast<char *>(iov.iov_base) + nbytes;
        iov.iov_len -= size_t(nbytes);
    }

    return data.length - iov.iov_len;
}

uint32 LocalSocket::availableBytesForReading()
{
    uint32 available = 0;
    if (ioctl(m_fd, FIONREAD, &available) < 0) {
        available = 0;
    }
    return available;
}

chunk LocalSocket::read(byte *buffer, uint32 maxSize)
{
    chunk ret(buffer, 0);

    while (ret.length < maxSize) {
        ssize_t nbytes = recv(m_fd, ret.ptr + ret.length, maxSize - ret.length, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // If we were notified for reading directly by the event dispatcher, we must be able to read at
            // least one byte before getting AGAIN aka EWOULDBLOCK - *however* the event loop might notify
            // something that is very eager to read everything (like Message::notifyRead()...) by reading
            // multiple times and in that case, we may be called in an attempt to read more when there is
            // currently no more data.
            // Just return zero bytes and no error in that case.
            if (errno == EAGAIN /* && iov.iov_len < maxSize */) {
                break;
            }
            close();
            return ret;
        }
        ret.length += size_t(nbytes);
    }

    return ret;
}

chunk LocalSocket::readWithFileDescriptors(byte *buffer, uint32 maxSize, vector<int> *fileDescriptors)
{
    chunk ret;
    if (maxSize <= 0) {
        return ret;
    }

    // recvmsg-with-control-message boilerplate
    struct msghdr recv_msg;
    char cmsgBuf[CMSG_SPACE(sizeof(int) * maxFds)];
    memset(cmsgBuf, 0, sizeof(cmsgBuf));

    recv_msg.msg_control = cmsgBuf;
    recv_msg.msg_controllen = sizeof(cmsgBuf);
    recv_msg.msg_name = 0;
    recv_msg.msg_namelen = 0;
    recv_msg.msg_flags = 0;

    struct iovec iov;
    recv_msg.msg_iov = &iov;
    recv_msg.msg_iovlen = 1;

    // end boilerplate

    ret.ptr = buffer;
    ret.length = 0;
    iov.iov_base = ret.ptr;
    iov.iov_len = maxSize;
    while (iov.iov_len > 0) {
        ssize_t nbytes = recvmsg(m_fd, &recv_msg, MSG_DONTWAIT);
        if (nbytes < 0) {
            if (errno == EINTR) {
                continue;
            }
            // If we were notified for reading directly by the event dispatcher, we must be able to read at
            // least one byte before getting AGAIN aka EWOULDBLOCK - *however* the event loop might notify
            // something that is very eager to read everything (like Message::notifyRead()...) by reading
            // multiple times and in that case, we may be called in an attempt to read more when there is
            // currently no more data.
            // Just return zero bytes and no error in that case.
            if (errno == EAGAIN /* && iov.iov_len < maxSize */) {
                break;
            }
            close();
            return ret;
        }
        ret.length += size_t(nbytes);
        iov.iov_base = static_cast<char *>(iov.iov_base) + nbytes;
        iov.iov_len -= size_t(nbytes);
    }

    // done reading "regular data", now read any file descriptors passed via control messages

    struct cmsghdr *c_msg = CMSG_FIRSTHDR(&recv_msg);
    if (c_msg && c_msg->cmsg_level == SOL_SOCKET && c_msg->cmsg_type == SCM_RIGHTS) {
        const int len = c_msg->cmsg_len / sizeof(int);
        int *cmsgData = reinterpret_cast<int *>(CMSG_DATA(c_msg));
        for (int i = 0; i < len; i++) {
            fileDescriptors->push_back(cmsgData[i]);
        }
    }

    return ret;
}

bool LocalSocket::isOpen()
{
    return m_fd != -1;
}

int LocalSocket::fileDescriptor() const
{
    return m_fd;
}

void LocalSocket::handleCanRead()
{
    if (availableBytesForReading()) {
        ITransport::handleCanRead();
    } else {
        // This should really only happen in error cases! ### TODO test?
        close();
    }
}
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   06/04/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNtuple                                                              //
//                                                                      //
// A simple tree restricted to a list of float variables only.          //
//                                                                      //
// Each variable goes to a separate branch.                             //
//                                                                      //
//  A Ntuple is created via                                             //
//     TNtuple(name,title,varlist,bufsize)                              //
//  It is filled via:                                                   //
//     TNtuple::Fill(*x)  or                                            //
//     TNtuple::Fill(v1,v2,v3.....)                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TNtuple.h"
#include "TTree.h"
#include "TBranch.h"
#include "TLeaf.h"
#include "TBrowser.h"
#include "Riostream.h"
#include "TClass.h"

#include <string>

ClassImp(TNtuple)

//______________________________________________________________________________
TNtuple::TNtuple(): TTree()
{
//*-*-*-*-*-*Default constructor for Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ==============================

   fNvar = 0;
   fArgs = 0;
}

//______________________________________________________________________________
TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Int_t bufsize)
       :TTree(name,title)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create an Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ================
//       The parameter varlist describes the list of the ntuple variables
//       separated by a colon:
//         example:  "x:y:z:energy"
//       For each variable in the list a separate branch is created.
//
//      NOTE:
//       -Use TTree to create branches with variables of different data types.
//       -Use TTree when the number of branches is large (> 100).
//*-*

   Int_t i;
   fNvar = 0;
   fArgs = 0;

//   Count number of variables (separated by :)
   Int_t nch = strlen(varlist);
   if (nch == 0) return;
   char *vars = new char[nch+1];
   strcpy(vars,varlist);
   Int_t *pvars = new Int_t[nch+1];
   fNvar = 1;
   pvars[0] = 0;
   for (i=1;i<nch;i++) {
      if (vars[i] == ':') {
         pvars[fNvar] = i+1;
         vars[i] = 0;
         fNvar++;
      }
   }
   fArgs = new Float_t[fNvar];

//  Create one branch for each variable
   for (i=0;i<fNvar;i++) {
      Int_t pv = pvars[i];
      TTree::Branch(&vars[pv],&fArgs[i],&vars[pv],bufsize);
   }

   delete [] vars;
   delete [] pvars;
}

//______________________________________________________________________________
TNtuple::~TNtuple()
{
//*-*-*-*-*-*Default destructor for an Ntuple*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ================================

   delete [] fArgs;
   fArgs = 0;
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddress(TBranch *branch)
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   if (branch) {
      Int_t index = fBranches.IndexOf(branch);
      if (index>=0) {
         branch->SetAddress(&fArgs[index]);
      }
   }
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddresses()
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   for (Int_t i = 0; i < fNvar; i++) {
      TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
      if (branch) branch->SetAddress(&fArgs[i]);
   }
}

//______________________________________________________________________________
void TNtuple::Browse(TBrowser *b)
{
   // Browse content of the ntuple

   fLeaves.Browse( b );
}

//______________________________________________________________________________
Int_t TNtuple::Fill()
{
//*-*-*-*-*-*-*-*-*Fill a Ntuple with current values in fArgs*-*-*-*-*-*-*
//*-*              ==========================================
// Note that this function is protected.
// Currently called only by TChain::Merge

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(const Float_t *x)
{
   // Fill a Ntuple with an array of floats

   // Store array x into buffer
   for (Int_t i=0;i<fNvar;i++)  {
      fArgs[i] = x[i];
   }

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(Float_t x0,Float_t x1,Float_t x2,Float_t x3,Float_t x4
              ,Float_t x5,Float_t x6,Float_t x7,Float_t x8,Float_t x9
              ,Float_t x10,Float_t x11,Float_t x12,Float_t x13,Float_t x14)
{
   // Fill a Ntuple: Each Ntuple item is an argument

   if (fNvar >  0) fArgs[0]  = x0;
   if (fNvar >  1) fArgs[1]  = x1;
   if (fNvar >  2) fArgs[2]  = x2;
   if (fNvar >  3) fArgs[3]  = x3;
   if (fNvar >  4) fArgs[4]  = x4;
   if (fNvar >  5) fArgs[5]  = x5;
   if (fNvar >  6) fArgs[6]  = x6;
   if (fNvar >  7) fArgs[7]  = x7;
   if (fNvar >  8) fArgs[8]  = x8;
   if (fNvar >  9) fArgs[9]  = x9;
   if (fNvar > 10) fArgs[10] = x10;
   if (fNvar > 11) fArgs[11] = x11;
   if (fNvar > 12) fArgs[12] = x12;
   if (fNvar > 13) fArgs[13] = x13;
   if (fNvar > 14) fArgs[14] = x14;

   return TTree::Fill();
}

//_______________________________________________________________________
Long64_t TNtuple::ReadFile(const char *filename, const char * /*branchDescriptor*/)
{
   // Read from filename as many columns as variables in the ntuple
   // the function returns the number of rows found in the file
   // The second argument "branchDescriptor" is currently not used.
   // Lines in the input file starting with "#" are ignored.

   Long64_t nlines = 0;
   ifstream in;
   in.open(filename);
   while (1) {
      if ( in.peek() != '#' ) {
         for (Int_t i=0;i<fNvar;i++) in >> fArgs[i];
         if (!in.good()) break;
         TTree::Fill();
         nlines++;
      }
      in.ignore(8192,'\n');
   }
   in.close();
   return nlines;
}

//_______________________________________________________________________
void TNtuple::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*              =========================================
   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         b.ReadClassBuffer(TNtuple::Class(), this, R__v, R__s, R__c);
      } else {
         //====process old versions before automatic schema evolution
         TTree::Streamer(b);
         b >> fNvar;
         b.CheckByteCount(R__s, R__c, TNtuple::IsA());
         //====end of old versions
      }
      if (fNvar <= 0) return;
      fArgs = new Float_t[fNvar];
      for (Int_t i=0;i<fNvar;i++) {
         TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
         if (branch) branch->SetAddress(&fArgs[i]);
      }
   } else {
      b.WriteClassBuffer(TNtuple::Class(),this);
   }
}
<commit_msg>replace calls to strcpy by strncpy<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   06/04/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNtuple                                                              //
//                                                                      //
// A simple tree restricted to a list of float variables only.          //
//                                                                      //
// Each variable goes to a separate branch.                             //
//                                                                      //
//  A Ntuple is created via                                             //
//     TNtuple(name,title,varlist,bufsize)                              //
//  It is filled via:                                                   //
//     TNtuple::Fill(*x)  or                                            //
//     TNtuple::Fill(v1,v2,v3.....)                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TNtuple.h"
#include "TTree.h"
#include "TBranch.h"
#include "TLeaf.h"
#include "TBrowser.h"
#include "Riostream.h"
#include "TClass.h"

#include <string>

ClassImp(TNtuple)

//______________________________________________________________________________
TNtuple::TNtuple(): TTree()
{
//*-*-*-*-*-*Default constructor for Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ==============================

   fNvar = 0;
   fArgs = 0;
}

//______________________________________________________________________________
TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Int_t bufsize)
       :TTree(name,title)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create an Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ================
//       The parameter varlist describes the list of the ntuple variables
//       separated by a colon:
//         example:  "x:y:z:energy"
//       For each variable in the list a separate branch is created.
//
//      NOTE:
//       -Use TTree to create branches with variables of different data types.
//       -Use TTree when the number of branches is large (> 100).
//*-*

   Int_t i;
   fNvar = 0;
   fArgs = 0;

//   Count number of variables (separated by :)
   Int_t nch = strlen(varlist);
   if (nch == 0) return;
   char *vars = new char[nch+1];
   strncpy(vars,varlist,nch);
   Int_t *pvars = new Int_t[nch+1];
   fNvar = 1;
   pvars[0] = 0;
   for (i=1;i<nch;i++) {
      if (vars[i] == ':') {
         pvars[fNvar] = i+1;
         vars[i] = 0;
         fNvar++;
      }
   }
   fArgs = new Float_t[fNvar];

//  Create one branch for each variable
   for (i=0;i<fNvar;i++) {
      Int_t pv = pvars[i];
      TTree::Branch(&vars[pv],&fArgs[i],&vars[pv],bufsize);
   }

   delete [] vars;
   delete [] pvars;
}

//______________________________________________________________________________
TNtuple::~TNtuple()
{
//*-*-*-*-*-*Default destructor for an Ntuple*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ================================

   delete [] fArgs;
   fArgs = 0;
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddress(TBranch *branch)
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   if (branch) {
      Int_t index = fBranches.IndexOf(branch);
      if (index>=0) {
         branch->SetAddress(&fArgs[index]);
      }
   }
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddresses()
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   for (Int_t i = 0; i < fNvar; i++) {
      TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
      if (branch) branch->SetAddress(&fArgs[i]);
   }
}

//______________________________________________________________________________
void TNtuple::Browse(TBrowser *b)
{
   // Browse content of the ntuple

   fLeaves.Browse( b );
}

//______________________________________________________________________________
Int_t TNtuple::Fill()
{
//*-*-*-*-*-*-*-*-*Fill a Ntuple with current values in fArgs*-*-*-*-*-*-*
//*-*              ==========================================
// Note that this function is protected.
// Currently called only by TChain::Merge

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(const Float_t *x)
{
   // Fill a Ntuple with an array of floats

   // Store array x into buffer
   for (Int_t i=0;i<fNvar;i++)  {
      fArgs[i] = x[i];
   }

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(Float_t x0,Float_t x1,Float_t x2,Float_t x3,Float_t x4
              ,Float_t x5,Float_t x6,Float_t x7,Float_t x8,Float_t x9
              ,Float_t x10,Float_t x11,Float_t x12,Float_t x13,Float_t x14)
{
   // Fill a Ntuple: Each Ntuple item is an argument

   if (fNvar >  0) fArgs[0]  = x0;
   if (fNvar >  1) fArgs[1]  = x1;
   if (fNvar >  2) fArgs[2]  = x2;
   if (fNvar >  3) fArgs[3]  = x3;
   if (fNvar >  4) fArgs[4]  = x4;
   if (fNvar >  5) fArgs[5]  = x5;
   if (fNvar >  6) fArgs[6]  = x6;
   if (fNvar >  7) fArgs[7]  = x7;
   if (fNvar >  8) fArgs[8]  = x8;
   if (fNvar >  9) fArgs[9]  = x9;
   if (fNvar > 10) fArgs[10] = x10;
   if (fNvar > 11) fArgs[11] = x11;
   if (fNvar > 12) fArgs[12] = x12;
   if (fNvar > 13) fArgs[13] = x13;
   if (fNvar > 14) fArgs[14] = x14;

   return TTree::Fill();
}

//_______________________________________________________________________
Long64_t TNtuple::ReadFile(const char *filename, const char * /*branchDescriptor*/)
{
   // Read from filename as many columns as variables in the ntuple
   // the function returns the number of rows found in the file
   // The second argument "branchDescriptor" is currently not used.
   // Lines in the input file starting with "#" are ignored.

   Long64_t nlines = 0;
   ifstream in;
   in.open(filename);
   while (1) {
      if ( in.peek() != '#' ) {
         for (Int_t i=0;i<fNvar;i++) in >> fArgs[i];
         if (!in.good()) break;
         TTree::Fill();
         nlines++;
      }
      in.ignore(8192,'\n');
   }
   in.close();
   return nlines;
}

//_______________________________________________________________________
void TNtuple::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*              =========================================
   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         b.ReadClassBuffer(TNtuple::Class(), this, R__v, R__s, R__c);
      } else {
         //====process old versions before automatic schema evolution
         TTree::Streamer(b);
         b >> fNvar;
         b.CheckByteCount(R__s, R__c, TNtuple::IsA());
         //====end of old versions
      }
      if (fNvar <= 0) return;
      fArgs = new Float_t[fNvar];
      for (Int_t i=0;i<fNvar;i++) {
         TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
         if (branch) branch->SetAddress(&fArgs[i]);
      }
   } else {
      b.WriteClassBuffer(TNtuple::Class(),this);
   }
}
<|endoftext|>