<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program 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 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, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_print.cpp
 *
 * @brief Evaluate and print the collected heaptrack data.
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <map>
#include <vector>
#include <memory>
#include <tuple>
#include <algorithm>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/program_options.hpp>

using namespace std;
namespace po = boost::program_options;

namespace {

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

ostream& operator<<(ostream& out, const AddressInformation& info)
{
    out << info.function;
    if (!info.file.empty()) {
        out << " in " << info.file << ':' << info.line;
    }
    return out;
}

struct InstructionPointer
{
    uintptr_t instructionPointer = 0;
    size_t parentIndex = 0;
    size_t moduleIndex = 0;
    size_t functionIndex = 0;
    size_t fileIndex = 0;
    int line = 0;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // bytes allocated in total
    size_t allocated;
    // amount of bytes leaked
    size_t leaked;
    // largest amount of bytes allocated
    size_t peak;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        instructionPointers.reserve(65536);
        strings.reserve(16384);
        // invalid string
        strings.push_back(string());
        // root node with invalid instruction pointer
        instructionPointers.push_back(InstructionPointer());
        allocations.reserve(16384);
        activeAllocations.reserve(65536);
    }

    void printBacktrace(InstructionPointer ip, ostream& out) const
    {
        while (ip.instructionPointer) {
            out << "0x" << hex << ip.instructionPointer << dec;
            if (ip.moduleIndex) {
                out << ' ' << stringify(ip.moduleIndex);
            } else {
                out << " <unknown module>";
            }
            if (ip.functionIndex) {
                out << ' ' << prettyFunction(stringify(ip.functionIndex));
            } else {
                out << " ??";
            }
            if (ip.fileIndex) {
                out << ' ' << stringify(ip.fileIndex) << ':' << ip.line;
            }
            out << '\n';

            if (mainIndex && ip.functionIndex == mainIndex) {
                break;
            }

            ip = instructionPointers[ip.parentIndex];
        };
    }

    Allocation& findAllocation(const size_t ipIndex)
    {
        auto it = lower_bound(allocations.begin(), allocations.end(), ipIndex,
                                [] (const Allocation& allocation, const size_t ipIndex) -> bool {
                                    return allocation.ipIndex < ipIndex;
                                });
        if (it == allocations.end() || it->ipIndex != ipIndex) {
            it = allocations.insert(it, {ipIndex, 0, 0, 0, 0});
        }
        return *it;
    }

    InstructionPointer findIp(const size_t ipIndex) const
    {
        if (ipIndex > instructionPointers.size()) {
            return {};
        } else {
            return instructionPointers[ipIndex];
        }
    }

    const string& stringify(const size_t stringId) const
    {
        if (stringId < strings.size()) {
            return strings.at(stringId);
        } else {
            return strings.at(0);
        }
    }

    void finalize()
    {
        auto it = find(strings.begin(), strings.end(), "main");
        if (it != strings.end()) {
            mainIndex = distance(strings.begin(), it);
        }
    }

    string prettyFunction(const string& function) const
    {
        if (!shortenTemplates) {
            return function;
        }
        string ret;
        ret.reserve(function.size());
        int depth = 0;
        for (size_t i = 0; i < function.size(); ++i) {
            const auto c = function[i];
            if (c == '<') {
                ++depth;
                if (depth == 1) {
                    ret.push_back(c);
                }
            } else if (c == '>') {
                --depth;
            }
            if (depth) {
                continue;
            }
            ret.push_back(c);
        }
        return ret;
    }

    bool shortenTemplates = false;

    vector<InstructionPointer> instructionPointers;
    vector<string> strings;
    vector<Allocation> allocations;
    unordered_map<uintptr_t, AllocationInfo> activeAllocations;

    size_t mainIndex = 0;

    map<size_t, size_t> sizeHistogram;
    size_t totalAllocated = 0;
    size_t totalAllocations = 0;
    size_t peak = 0;
    size_t leaked = 0;
};

}

int main(int argc, char** argv)
{
    po::options_description desc("Options");
    desc.add_options()
        ("file,f", po::value<string>()->required(), "The heaptrack data file to print.")
        ("shorten-templates,t", po::value<bool>()->default_value(true), "Shorten template identifiers.")
        ("print-peaks,p", po::value<bool>()->default_value(true), "Print backtraces to top allocators, sorted by peak consumption.")
        ("print-allocators,a", po::value<bool>()->default_value(true), "Print backtraces to top allocators, sorted by number of calls to allocation functions.")
        ("print-leaks,l", po::value<bool>()->default_value(false), "Print backtraces to leaked memory allocations.")
        ("print-histogram,h", po::value<bool>()->default_value(false), "Print allocation size histogram.")
        ("print-overall-allocated,o", po::value<bool>()->default_value(false), "Print top overall allocators, ignoring memory frees.")
        ("help,h", "Show this help message.");
    po::positional_options_description p;
    p.add("file", -1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv)
                    .options(desc).positional(p).run(), vm);
        po::notify(vm);
    } catch (const po::error& error) {
        cerr << "ERROR: " << error.what() << endl
             << endl << desc << endl;
        return 1;
    }

    if (vm.count("help")) {
        cout << desc << endl;
        return 1;
    }

    AccumulatedTraceData data;

    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);

    const auto inputFile = vm["file"].as<string>();
    data.shortenTemplates = vm["shorten-templates"].as<bool>();
    const bool printHistogram = vm["print-histogram"].as<bool>();
    const bool printLeaks = vm["print-leaks"].as<bool>();
    const bool printOverallAlloc = vm["print-overall-allocated"].as<bool>();
    const bool printPeaks = vm["print-peaks"].as<bool>();
    const bool printAllocs = vm["print-allocators"].as<bool>();

    string fileName(inputFile);
    const bool isCompressed = boost::algorithm::ends_with(fileName, ".gz");
    ifstream file(fileName, isCompressed ? ios_base::in | ios_base::binary : ios_base::in);

    if (!file.is_open()) {
        cerr << "Failed to open heaptrack log file: " << inputFile << endl
             << endl << desc << endl;
        return 1;
    }

    cout << "reading file \"" << fileName << "\" - please wait, this might take some time..." << endl;

    boost::iostreams::filtering_istream in;
    if (isCompressed) {
        in.push(boost::iostreams::gzip_decompressor());
    }
    in.push(file);

    string line;
    line.reserve(1024);

    stringstream lineIn(ios_base::in);
    lineIn << hex;

    while (in.good()) {
        getline(in, line);
        if (line.empty()) {
            continue;
        }
        const char mode = line[0];
        lineIn.str(line);
        lineIn.clear();
        // skip mode and leading whitespace
        lineIn.seekg(2);
        if (mode == 's') {
            data.strings.push_back(line.substr(2));
        } else if (mode == 'i') {
            InstructionPointer ip;
            lineIn >> ip.instructionPointer;
            lineIn >> ip.parentIndex;
            lineIn >> ip.moduleIndex;
            lineIn >> ip.functionIndex;
            lineIn >> ip.fileIndex;
            lineIn >> ip.line;
            data.instructionPointers.push_back(ip);
        } else if (mode == '+') {
            size_t size = 0;
            lineIn >> size;
            size_t ipId = 0;
            lineIn >> ipId;
            uintptr_t ptr = 0;
            lineIn >> ptr;
            if (lineIn.bad()) {
                cerr << "failed to parse line: " << line << endl;
                return 1;
            }

            data.activeAllocations[ptr] = {ipId, size};

            auto& allocation = data.findAllocation(ipId);
            allocation.leaked += size;
            allocation.allocated += size;
            ++allocation.allocations;
            if (allocation.leaked > allocation.peak) {
                allocation.peak = allocation.leaked;
            }
            data.totalAllocated += size;
            ++data.totalAllocations;
            data.leaked += size;
            if (data.leaked > data.peak) {
                data.peak = data.leaked;
            }
            ++data.sizeHistogram[size];
        } else if (mode == '-') {
            uintptr_t ptr = 0;
            lineIn >> ptr;
            if (lineIn.bad()) {
                cerr << "failed to parse line: " << line << endl;
                return 1;
            }
            auto ip = data.activeAllocations.find(ptr);
            if (ip == data.activeAllocations.end()) {
                cerr << "unknown pointer in line: " << line << endl;
                continue;
            }
            const auto info = ip->second;
            data.activeAllocations.erase(ip);

            auto& allocation = data.findAllocation(info.ipIndex);
            if (!allocation.allocations || allocation.leaked < info.size) {
                cerr << "inconsistent allocation info, underflowed allocations of " << info.ipIndex << endl;
                allocation.leaked = 0;
                allocation.allocations = 0;
            } else {
                allocation.leaked -= info.size;
            }
            data.leaked -= info.size;
        } else {
            cerr << "failed to parse line: " << line << endl;
        }
    }

    cout << "finished reading file, now analyzing data" << endl;

    data.finalize();

    if (printAllocs) {
        // sort by amount of allocations
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.allocations > r.allocations;
        });
        cout << "MOST ALLOCATIONS" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.allocations << " allocations at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printOverallAlloc) {
        // sort by amount of bytes allocated
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.allocated > r.allocated;
        });
        cout << "MOST ALLOCATED OVER TIME (ignoring deallocations)" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.allocated << " bytes allocated at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printPeaks) {
        // sort by peak memory consumption
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.peak > r.peak;
        });
        cout << "PEAK ALLOCATIONS" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.peak << " bytes allocated at peak:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printLeaks) {
        // sort by amount of leaks
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.leaked < r.leaked;
        });

        size_t totalLeakAllocations = 0;
        for (const auto& allocation : data.allocations) {
            if (!allocation.leaked) {
                continue;
            }
            totalLeakAllocations += allocation.allocations;

            cout << allocation.leaked << " bytes leaked in " << allocation.allocations << " allocations at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << data.leaked << " bytes leaked in total from " << totalLeakAllocations << " allocations" << endl;
    }

    cout << data.totalAllocated << " bytes allocated in total over " << data.totalAllocations
         << " allocations, peak consumption: " << data.peak << " bytes" << endl;
    cout << endl;

    if (printHistogram) {
        cout << "size histogram: " << endl;
        for (auto entry : data.sizeHistogram) {
            cout << entry.first << "\t" << entry.second << endl;
        }
    }

    return 0;
}
<commit_msg>Do not clash --print-histogram with --help.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program 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 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, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_print.cpp
 *
 * @brief Evaluate and print the collected heaptrack data.
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <map>
#include <vector>
#include <memory>
#include <tuple>
#include <algorithm>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/program_options.hpp>

using namespace std;
namespace po = boost::program_options;

namespace {

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

ostream& operator<<(ostream& out, const AddressInformation& info)
{
    out << info.function;
    if (!info.file.empty()) {
        out << " in " << info.file << ':' << info.line;
    }
    return out;
}

struct InstructionPointer
{
    uintptr_t instructionPointer = 0;
    size_t parentIndex = 0;
    size_t moduleIndex = 0;
    size_t functionIndex = 0;
    size_t fileIndex = 0;
    int line = 0;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // bytes allocated in total
    size_t allocated;
    // amount of bytes leaked
    size_t leaked;
    // largest amount of bytes allocated
    size_t peak;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        instructionPointers.reserve(65536);
        strings.reserve(16384);
        // invalid string
        strings.push_back(string());
        // root node with invalid instruction pointer
        instructionPointers.push_back(InstructionPointer());
        allocations.reserve(16384);
        activeAllocations.reserve(65536);
    }

    void printBacktrace(InstructionPointer ip, ostream& out) const
    {
        while (ip.instructionPointer) {
            out << "0x" << hex << ip.instructionPointer << dec;
            if (ip.moduleIndex) {
                out << ' ' << stringify(ip.moduleIndex);
            } else {
                out << " <unknown module>";
            }
            if (ip.functionIndex) {
                out << ' ' << prettyFunction(stringify(ip.functionIndex));
            } else {
                out << " ??";
            }
            if (ip.fileIndex) {
                out << ' ' << stringify(ip.fileIndex) << ':' << ip.line;
            }
            out << '\n';

            if (mainIndex && ip.functionIndex == mainIndex) {
                break;
            }

            ip = instructionPointers[ip.parentIndex];
        };
    }

    Allocation& findAllocation(const size_t ipIndex)
    {
        auto it = lower_bound(allocations.begin(), allocations.end(), ipIndex,
                                [] (const Allocation& allocation, const size_t ipIndex) -> bool {
                                    return allocation.ipIndex < ipIndex;
                                });
        if (it == allocations.end() || it->ipIndex != ipIndex) {
            it = allocations.insert(it, {ipIndex, 0, 0, 0, 0});
        }
        return *it;
    }

    InstructionPointer findIp(const size_t ipIndex) const
    {
        if (ipIndex > instructionPointers.size()) {
            return {};
        } else {
            return instructionPointers[ipIndex];
        }
    }

    const string& stringify(const size_t stringId) const
    {
        if (stringId < strings.size()) {
            return strings.at(stringId);
        } else {
            return strings.at(0);
        }
    }

    void finalize()
    {
        auto it = find(strings.begin(), strings.end(), "main");
        if (it != strings.end()) {
            mainIndex = distance(strings.begin(), it);
        }
    }

    string prettyFunction(const string& function) const
    {
        if (!shortenTemplates) {
            return function;
        }
        string ret;
        ret.reserve(function.size());
        int depth = 0;
        for (size_t i = 0; i < function.size(); ++i) {
            const auto c = function[i];
            if (c == '<') {
                ++depth;
                if (depth == 1) {
                    ret.push_back(c);
                }
            } else if (c == '>') {
                --depth;
            }
            if (depth) {
                continue;
            }
            ret.push_back(c);
        }
        return ret;
    }

    bool shortenTemplates = false;

    vector<InstructionPointer> instructionPointers;
    vector<string> strings;
    vector<Allocation> allocations;
    unordered_map<uintptr_t, AllocationInfo> activeAllocations;

    size_t mainIndex = 0;

    map<size_t, size_t> sizeHistogram;
    size_t totalAllocated = 0;
    size_t totalAllocations = 0;
    size_t peak = 0;
    size_t leaked = 0;
};

}

int main(int argc, char** argv)
{
    po::options_description desc("Options");
    desc.add_options()
        ("file,f", po::value<string>()->required(), "The heaptrack data file to print.")
        ("shorten-templates,t", po::value<bool>()->default_value(true), "Shorten template identifiers.")
        ("print-peaks,p", po::value<bool>()->default_value(true), "Print backtraces to top allocators, sorted by peak consumption.")
        ("print-allocators,a", po::value<bool>()->default_value(true), "Print backtraces to top allocators, sorted by number of calls to allocation functions.")
        ("print-leaks,l", po::value<bool>()->default_value(false), "Print backtraces to leaked memory allocations.")
        ("print-histogram,H", po::value<bool>()->default_value(false), "Print allocation size histogram.")
        ("print-overall-allocated,o", po::value<bool>()->default_value(false), "Print top overall allocators, ignoring memory frees.")
        ("help,h", "Show this help message.");
    po::positional_options_description p;
    p.add("file", -1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv)
                    .options(desc).positional(p).run(), vm);
        po::notify(vm);
    } catch (const po::error& error) {
        cerr << "ERROR: " << error.what() << endl
             << endl << desc << endl;
        return 1;
    }

    if (vm.count("help")) {
        cout << desc << endl;
        return 1;
    }

    AccumulatedTraceData data;

    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);

    const auto inputFile = vm["file"].as<string>();
    data.shortenTemplates = vm["shorten-templates"].as<bool>();
    const bool printHistogram = vm["print-histogram"].as<bool>();
    const bool printLeaks = vm["print-leaks"].as<bool>();
    const bool printOverallAlloc = vm["print-overall-allocated"].as<bool>();
    const bool printPeaks = vm["print-peaks"].as<bool>();
    const bool printAllocs = vm["print-allocators"].as<bool>();

    string fileName(inputFile);
    const bool isCompressed = boost::algorithm::ends_with(fileName, ".gz");
    ifstream file(fileName, isCompressed ? ios_base::in | ios_base::binary : ios_base::in);

    if (!file.is_open()) {
        cerr << "Failed to open heaptrack log file: " << inputFile << endl
             << endl << desc << endl;
        return 1;
    }

    cout << "reading file \"" << fileName << "\" - please wait, this might take some time..." << endl;

    boost::iostreams::filtering_istream in;
    if (isCompressed) {
        in.push(boost::iostreams::gzip_decompressor());
    }
    in.push(file);

    string line;
    line.reserve(1024);

    stringstream lineIn(ios_base::in);
    lineIn << hex;

    while (in.good()) {
        getline(in, line);
        if (line.empty()) {
            continue;
        }
        const char mode = line[0];
        lineIn.str(line);
        lineIn.clear();
        // skip mode and leading whitespace
        lineIn.seekg(2);
        if (mode == 's') {
            data.strings.push_back(line.substr(2));
        } else if (mode == 'i') {
            InstructionPointer ip;
            lineIn >> ip.instructionPointer;
            lineIn >> ip.parentIndex;
            lineIn >> ip.moduleIndex;
            lineIn >> ip.functionIndex;
            lineIn >> ip.fileIndex;
            lineIn >> ip.line;
            data.instructionPointers.push_back(ip);
        } else if (mode == '+') {
            size_t size = 0;
            lineIn >> size;
            size_t ipId = 0;
            lineIn >> ipId;
            uintptr_t ptr = 0;
            lineIn >> ptr;
            if (lineIn.bad()) {
                cerr << "failed to parse line: " << line << endl;
                return 1;
            }

            data.activeAllocations[ptr] = {ipId, size};

            auto& allocation = data.findAllocation(ipId);
            allocation.leaked += size;
            allocation.allocated += size;
            ++allocation.allocations;
            if (allocation.leaked > allocation.peak) {
                allocation.peak = allocation.leaked;
            }
            data.totalAllocated += size;
            ++data.totalAllocations;
            data.leaked += size;
            if (data.leaked > data.peak) {
                data.peak = data.leaked;
            }
            ++data.sizeHistogram[size];
        } else if (mode == '-') {
            uintptr_t ptr = 0;
            lineIn >> ptr;
            if (lineIn.bad()) {
                cerr << "failed to parse line: " << line << endl;
                return 1;
            }
            auto ip = data.activeAllocations.find(ptr);
            if (ip == data.activeAllocations.end()) {
                cerr << "unknown pointer in line: " << line << endl;
                continue;
            }
            const auto info = ip->second;
            data.activeAllocations.erase(ip);

            auto& allocation = data.findAllocation(info.ipIndex);
            if (!allocation.allocations || allocation.leaked < info.size) {
                cerr << "inconsistent allocation info, underflowed allocations of " << info.ipIndex << endl;
                allocation.leaked = 0;
                allocation.allocations = 0;
            } else {
                allocation.leaked -= info.size;
            }
            data.leaked -= info.size;
        } else {
            cerr << "failed to parse line: " << line << endl;
        }
    }

    cout << "finished reading file, now analyzing data" << endl;

    data.finalize();

    if (printAllocs) {
        // sort by amount of allocations
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.allocations > r.allocations;
        });
        cout << "MOST ALLOCATIONS" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.allocations << " allocations at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printOverallAlloc) {
        // sort by amount of bytes allocated
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.allocated > r.allocated;
        });
        cout << "MOST ALLOCATED OVER TIME (ignoring deallocations)" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.allocated << " bytes allocated at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printPeaks) {
        // sort by peak memory consumption
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.peak > r.peak;
        });
        cout << "PEAK ALLOCATIONS" << endl;
        for (size_t i = 0; i < min(10lu, data.allocations.size()); ++i) {
            const auto& allocation = data.allocations[i];
            cout << allocation.peak << " bytes allocated at peak:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << endl;
    }

    if (printLeaks) {
        // sort by amount of leaks
        sort(data.allocations.begin(), data.allocations.end(), [] (const Allocation& l, const Allocation &r) {
            return l.leaked < r.leaked;
        });

        size_t totalLeakAllocations = 0;
        for (const auto& allocation : data.allocations) {
            if (!allocation.leaked) {
                continue;
            }
            totalLeakAllocations += allocation.allocations;

            cout << allocation.leaked << " bytes leaked in " << allocation.allocations << " allocations at:" << endl;
            data.printBacktrace(data.findIp(allocation.ipIndex), cout);
            cout << endl;
        }
        cout << data.leaked << " bytes leaked in total from " << totalLeakAllocations << " allocations" << endl;
    }

    cout << data.totalAllocated << " bytes allocated in total over " << data.totalAllocations
         << " allocations, peak consumption: " << data.peak << " bytes" << endl;
    cout << endl;

    if (printHistogram) {
        cout << "size histogram: " << endl;
        for (auto entry : data.sizeHistogram) {
            cout << entry.first << "\t" << entry.second << endl;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdbool.h>
#include <stdint.h>

#include <string>
#include <vector>
#include <set>
#include <queue>
#include <iostream>

#include "tuneables.h"
#include "debug.h"
#include "oriutil.h"
#include "object.h"
#include "largeblob.h"

#include "debug.h"
#include "dag.h"
#include "repo.h"
#include "localrepo.h"
#include "sshrepo.h"

using namespace std;

ObjectHash EMPTY_COMMIT =
ObjectHash::fromHex("0000000000000000000000000000000000000000000000000000000000000000");

#ifdef ORI_USE_SHA256
ObjectHash EMPTYFILE_HASH =
ObjectHash::fromHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
#endif
#ifdef ORI_USE_SKEIN
ObjectHash EMPTYFILE_HASH =
ObjectHash::fromHex("c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba");
#endif

/*
 * Repo
 */

Repo::Repo() {
}

Repo::~Repo() {
}

/*
 * High-level operations
 */

void
Repo::copyFrom(Object *other)
{
    addObject(other->getInfo().type, other->getInfo().hash, other->getPayload());
}

/*
 * Add a blob to the repository. This is a low-level interface.
 */
ObjectHash
Repo::addBlob(ObjectType type, const string &blob)
{
    ObjectHash hash = Util_HashString(blob);
    addObject(type, hash, blob);
    return hash;
}

bytestream *
Repo::getObjects(const std::deque<ObjectHash> &objs)
{
    ObjectHashVec vec;
    for (size_t i = 0; i < objs.size(); i++) {
        vec.push_back(objs[i]);
    }
    return getObjects(vec);
}

/*
 * Add a file to the repository. This is a low-level interface.
 */
ObjectHash
Repo::addSmallFile(const string &path)
{
    diskstream ds(path);
    return addBlob(ObjectInfo::Blob, ds.readAll());
}

/*
 * Add a file to the repository. This is a low-level interface.
 */
pair<ObjectHash, ObjectHash>
Repo::addLargeFile(const string &path)
{
    string blob;
    string hash;
    LargeBlob lb = LargeBlob(this);

    lb.chunkFile(path);
    blob = lb.getBlob();

    // TODO: this should only be called when committing,
    // we'll take care of backrefs then
    /*if (!hasObject(hash)) {
        map<uint64_t, LBlobEntry>::iterator it;

        for (it = lb.parts.begin(); it != lb.parts.end(); it++) {
            addBackref((*it).second.hash);
        }
    }*/

    return make_pair(addBlob(ObjectInfo::LargeBlob, blob), lb.totalHash);
}

/*
 * Add a file to the repository. This is an internal interface that pusheds the
 * work to addLargeFile or addSmallFile based on our size threshold.
 */
pair<ObjectHash, ObjectHash>
Repo::addFile(const string &path)
{
    size_t sz = Util_FileSize(path);

    if (sz > LARGEFILE_MINIMUM)
        return addLargeFile(path);
    else
        return make_pair(addSmallFile(path), ObjectHash());
}

Tree
Repo::getTree(const ObjectHash &treeId)
{
    Object::sp o(getObject(treeId));
    string blob = o->getPayload();

    ASSERT(treeId == EMPTYFILE_HASH || o->getInfo().type == ObjectInfo::Tree);

    Tree t;
    t.fromBlob(blob);

    return t;
}

Commit
Repo::getCommit(const ObjectHash &commitId)
{
    Object::sp o(getObject(commitId));
    string blob = o->getPayload();

    ASSERT(commitId == EMPTYFILE_HASH || o->getInfo().type == ObjectInfo::Commit);

    Commit c;
    if (blob.size() == 0) {
        printf("Error getting commit blob\n");
        PANIC();
        return c;
    }
    c.fromBlob(blob);

    return c;
}

DAG<ObjectHash, Commit>
Repo::getCommitDag()
{
    vector<Commit> commits = listCommits();
    vector<Commit>::iterator it;
    DAG<ObjectHash, Commit> cDag = DAG<ObjectHash, Commit>();

    cDag.addNode(ObjectHash(), Commit());
    for (it = commits.begin(); it != commits.end(); it++) {
	cDag.addNode((*it).hash(), (*it));
    }

    for (it = commits.begin(); it != commits.end(); it++) {
	pair<ObjectHash, ObjectHash> p = (*it).getParents();
	cDag.addEdge(p.first, (*it).hash());
	if (!p.second.isEmpty())
	    cDag.addEdge(p.first, it->hash());
    }

    return cDag;
}

<commit_msg>Exception for missing object<commit_after>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdbool.h>
#include <stdint.h>

#include <string>
#include <vector>
#include <set>
#include <queue>
#include <iostream>

#include "tuneables.h"
#include "debug.h"
#include "oriutil.h"
#include "object.h"
#include "largeblob.h"

#include "debug.h"
#include "dag.h"
#include "repo.h"
#include "localrepo.h"
#include "sshrepo.h"

using namespace std;

ObjectHash EMPTY_COMMIT =
ObjectHash::fromHex("0000000000000000000000000000000000000000000000000000000000000000");

#ifdef ORI_USE_SHA256
ObjectHash EMPTYFILE_HASH =
ObjectHash::fromHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
#endif
#ifdef ORI_USE_SKEIN
ObjectHash EMPTYFILE_HASH =
ObjectHash::fromHex("c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba");
#endif

/*
 * Repo
 */

Repo::Repo() {
}

Repo::~Repo() {
}

/*
 * High-level operations
 */

void
Repo::copyFrom(Object *other)
{
    addObject(other->getInfo().type, other->getInfo().hash, other->getPayload());
}

/*
 * Add a blob to the repository. This is a low-level interface.
 */
ObjectHash
Repo::addBlob(ObjectType type, const string &blob)
{
    ObjectHash hash = Util_HashString(blob);
    addObject(type, hash, blob);
    return hash;
}

bytestream *
Repo::getObjects(const std::deque<ObjectHash> &objs)
{
    ObjectHashVec vec;
    for (size_t i = 0; i < objs.size(); i++) {
        vec.push_back(objs[i]);
    }
    return getObjects(vec);
}

/*
 * Add a file to the repository. This is a low-level interface.
 */
ObjectHash
Repo::addSmallFile(const string &path)
{
    diskstream ds(path);
    return addBlob(ObjectInfo::Blob, ds.readAll());
}

/*
 * Add a file to the repository. This is a low-level interface.
 */
pair<ObjectHash, ObjectHash>
Repo::addLargeFile(const string &path)
{
    string blob;
    string hash;
    LargeBlob lb = LargeBlob(this);

    lb.chunkFile(path);
    blob = lb.getBlob();

    // TODO: this should only be called when committing,
    // we'll take care of backrefs then
    /*if (!hasObject(hash)) {
        map<uint64_t, LBlobEntry>::iterator it;

        for (it = lb.parts.begin(); it != lb.parts.end(); it++) {
            addBackref((*it).second.hash);
        }
    }*/

    return make_pair(addBlob(ObjectInfo::LargeBlob, blob), lb.totalHash);
}

/*
 * Add a file to the repository. This is an internal interface that pusheds the
 * work to addLargeFile or addSmallFile based on our size threshold.
 */
pair<ObjectHash, ObjectHash>
Repo::addFile(const string &path)
{
    size_t sz = Util_FileSize(path);

    if (sz > LARGEFILE_MINIMUM)
        return addLargeFile(path);
    else
        return make_pair(addSmallFile(path), ObjectHash());
}

Tree
Repo::getTree(const ObjectHash &treeId)
{
    Object::sp o(getObject(treeId));
    if (!o.get()) {
        throw std::runtime_error("Object not found");
    }
    string blob = o->getPayload();

    ASSERT(treeId == EMPTYFILE_HASH || o->getInfo().type == ObjectInfo::Tree);

    Tree t;
    t.fromBlob(blob);

    return t;
}

Commit
Repo::getCommit(const ObjectHash &commitId)
{
    Object::sp o(getObject(commitId));
    string blob = o->getPayload();

    ASSERT(commitId == EMPTYFILE_HASH || o->getInfo().type == ObjectInfo::Commit);

    Commit c;
    if (blob.size() == 0) {
        printf("Error getting commit blob\n");
        PANIC();
        return c;
    }
    c.fromBlob(blob);

    return c;
}

DAG<ObjectHash, Commit>
Repo::getCommitDag()
{
    vector<Commit> commits = listCommits();
    vector<Commit>::iterator it;
    DAG<ObjectHash, Commit> cDag = DAG<ObjectHash, Commit>();

    cDag.addNode(ObjectHash(), Commit());
    for (it = commits.begin(); it != commits.end(); it++) {
	cDag.addNode((*it).hash(), (*it));
    }

    for (it = commits.begin(); it != commits.end(); it++) {
	pair<ObjectHash, ObjectHash> p = (*it).getParents();
	cDag.addEdge(p.first, (*it).hash());
	if (!p.second.isEmpty())
	    cDag.addEdge(p.first, it->hash());
    }

    return cDag;
}

<|endoftext|>


<commit_before>/*
 * This file is part of crash-reporter
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>
 * Author: Raimo Gratseff <ext-raimo.gratseff@nokia.com>
 *
 * Copyright (C) 2013 Jolla Ltd.
 * Contact: Jakub Adam <jakub.adam@jollamobile.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

// System includes.

#include <QDebug>
#include <QDBusConnection>

// User includes.

#include "creporterautouploader.h"
#include "creporternamespace.h"
#include "creporternwsessionmgr.h"
#include "creportersavedstate.h"
#include "creporteruploadqueue.h"
#include "creporteruploaditem.h"
#include "creporteruploadengine.h"
#include "creporternotification.h"
#include "creporterprivacysettingsmodel.h"

#include "autouploader_adaptor.h" // generated

/*! @class CReporterAutoUploaderPrivate
  * @brief Private CReporterAutoUploaderPrivate class.
  *
  * @sa CReporterAutoUploader
  */
class CReporterAutoUploaderPrivate
{
    public:

        //! @arg Upload engine.
        CReporterUploadEngine *engine;
        //! @arg Upload queue.
        CReporterUploadQueue queue;
        //! @arg Is the service active.
        bool activated;
        //! @arg files that have been added to upload queue during this auto uploader session
        QStringList addedFiles;
        /*! Notification object giving user a notice that upload is in progress.*/
        CReporterNotification *progressNotification;
        /*! Notification object giving user a notice of successful uploads.*/
        CReporterNotification *successNotification;
        /*! Notification object giving user a notice of failed uploads.*/
        CReporterNotification *failedNotification;

};

CReporterAutoUploader::CReporterAutoUploader() : d_ptr(new CReporterAutoUploaderPrivate)
{
    d_ptr->engine = 0;
    d_ptr->activated = false;
    d_ptr->progressNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
            0, this);
    d_ptr->successNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
                    CReporterSavedState::instance()->uploadSuccessNotificationId(),
                    this);
    d_ptr->failedNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
                    CReporterSavedState::instance()->uploadFailedNotificationId(),
                    this);

    // Create adaptor class. Needs to be taken from the stack.
    new AutoUploaderAdaptor(this);
    // Register service name and object.
    QDBusConnection::sessionBus().registerService(CReporter::AutoUploaderServiceName);
    QDBusConnection::sessionBus().registerObject(CReporter::AutoUploaderObjectPath, this);
    qDebug() << __PRETTY_FUNCTION__ << "Started Auto Uploader service.";
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::~CReporterAutoUploader
// ----------------------------------------------------------------------------
CReporterAutoUploader::~CReporterAutoUploader()
{
    quit();
    if (d_ptr)
    {
        delete d_ptr;
        d_ptr = 0;
    }

    CReporterSavedState::freeSingleton();

    qDebug() << __PRETTY_FUNCTION__ << "Service closed.";

}

bool CReporterAutoUploader::uploadFiles(const QStringList &fileList,
        bool obeyNetworkRestrictions)
{
    qDebug() << __PRETTY_FUNCTION__ << "Received a list of files to upload.";

    if (fileList.isEmpty())
        return false;

    if (!d_ptr->activated)
    {
        d_ptr->engine = new CReporterUploadEngine(&d_ptr->queue);
        d_ptr->activated = true;
        connect(d_ptr->engine, SIGNAL(finished(int, int, int)), SLOT(engineFinished(int, int, int)));
    }

    if (obeyNetworkRestrictions &&
        !CReporterNwSessionMgr::canUseNetworkConnection()) {
        qDebug() << __PRETTY_FUNCTION__
                 << "No unpaid network connection available, aborting crash report upload.";
        QTimer::singleShot(0, this, SLOT(quit()));
        return false;
    }

    foreach (QString filename, fileList)
    {
        if (!d_ptr->addedFiles.contains(filename))
        {
            qDebug() << __PRETTY_FUNCTION__ << "Adding to upload queue: " << filename;
            // CReporterUploadQueue class will own the CReporterUploadItem instance.
            d_ptr->queue.enqueue(new CReporterUploadItem(filename));
            d_ptr->addedFiles << filename;
        }
        else
        {
            qDebug() << __PRETTY_FUNCTION__ << filename << "was not added to queue because it had already been added before";
        }
    }

    if (CReporterPrivacySettingsModel::instance()->notificationsEnabled())
    {
        d_ptr->progressNotification->update(
                //% "Uploading reports"
                qtTrId("crash_reporter-notify-uploading_reports"),
                //% "%1 report(s) to upload"
                qtTrId("crash_reporter-notify-num_to_upload").arg(fileList.count()));
    }

    return true;
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::quit
// ----------------------------------------------------------------------------
void CReporterAutoUploader::quit()
{
    qDebug() << __PRETTY_FUNCTION__ << "Quit auto uploader.";
    if (d_ptr->engine)
    {
        if (d_ptr->activated)
        {
            qDebug() << __PRETTY_FUNCTION__ << "Engine active -> cancelling";
            d_ptr->activated = false;
            d_ptr->engine->cancelAll();
        }
        qDebug() << __PRETTY_FUNCTION__ << "Deleting engine.";
        disconnect(d_ptr->engine, SIGNAL(finished(int, int, int)), this, SLOT(engineFinished(int, int, int)));
        d_ptr->engine->deleteLater();
        d_ptr->engine = 0;
    }
    qApp->quit();
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::engineFinished
// ----------------------------------------------------------------------------
void CReporterAutoUploader::engineFinished(int error, int sent, int total)
{
    QString message;

    // Construct message.
    switch (error)
    {
        case CReporterUploadEngine::NoError:
            //% "%1 report(s) uploaded successfully."
            message = qtTrId("qtn_%1_crash_reports_uploaded_successfully_text").arg(total);
            break;
        case CReporterUploadEngine::ProtocolError:
        case CReporterUploadEngine::ConnectionNotAvailable:
        case CReporterUploadEngine::ConnectionClosed:
            //% "Failed to upload report(s)."
            message = qtTrId("qtn_failed_to_send_crash_reports_text");
            //% "
Upload results: %1 files attempted %2 files succeeded."
            message += qtTrId("qtn_%1_files_attempted_%2_files_succeeded_text").arg(total).arg(sent);
            break;
        default:
        // We should never enter here.
        break;
    };

    if (error != CReporterUploadEngine::NoError)
    {
        // Add error reason.
        if (error == CReporterUploadEngine::ConnectionNotAvailable)
        {
            //% "
Reason: Failed to create internet connection."
            message += qtTrId("qtn_reason_failed_to_create_internet_connection_text");
        }
        else
        {
            QString reason = d_ptr->engine->lastError();
            if (!reason.isEmpty())
            {
                // If reason is available, append it.
                //% "
Reason: %1."
                message += qtTrId("qtn_reason_%1_text").arg(reason);
            }
            else
            {
                // Use default error.
                //% "
Reason: Unknown."
                message += qtTrId("qtn_reason_unknown_text");
            }
        }
    }

    if (CReporterPrivacySettingsModel::instance()->notificationsEnabled()) {
        d_ptr->progressNotification->remove();

        if (total > sent) {
            int failures = total - sent;
            d_ptr->failedNotification->update(
                    //% "Failed to send all reports"
                    qtTrId("crash_reporter-notify-send_failed"),
                    //% "%1 uploads failed"
                    qtTrId("crash_reporter-notify-num_failed").arg(failures),
                    failures);
        } else {
            d_ptr->failedNotification->remove();
        }

        CReporterSavedState *state = CReporterSavedState::instance();

        if (sent > 0) {
            sent += state->uploadSuccessCount();

            QString summary = (sent == 1) ?
                    //% "Report uploaded"
                    qtTrId("crash_reporter-notify-report_uploaded") :
                    //% "Reports uploaded"
                    qtTrId("crash_reporter-notify-reports_uploaded");
            d_ptr->successNotification->update(summary, QString(), sent);
        }

        state->setUploadSuccessNotificationId(d_ptr->successNotification->id());
        state->setUploadFailedNotificationId(d_ptr->failedNotification->id());
        state->setUploadSuccessCount(sent);
    }

    qDebug() << __PRETTY_FUNCTION__ << "Message: " << message;

    d_ptr->activated = false;
    quit();
}

#include "moc_autouploader_adaptor.cpp"
<commit_msg>[autouploader] Fix translation source string not read<commit_after>/*
 * This file is part of crash-reporter
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Ville Ilvonen <ville.p.ilvonen@nokia.com>
 * Author: Raimo Gratseff <ext-raimo.gratseff@nokia.com>
 *
 * Copyright (C) 2013 Jolla Ltd.
 * Contact: Jakub Adam <jakub.adam@jollamobile.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

// System includes.

#include <QDebug>
#include <QDBusConnection>

// User includes.

#include "creporterautouploader.h"
#include "creporternamespace.h"
#include "creporternwsessionmgr.h"
#include "creportersavedstate.h"
#include "creporteruploadqueue.h"
#include "creporteruploaditem.h"
#include "creporteruploadengine.h"
#include "creporternotification.h"
#include "creporterprivacysettingsmodel.h"

#include "autouploader_adaptor.h" // generated

/*! @class CReporterAutoUploaderPrivate
  * @brief Private CReporterAutoUploaderPrivate class.
  *
  * @sa CReporterAutoUploader
  */
class CReporterAutoUploaderPrivate
{
    public:

        //! @arg Upload engine.
        CReporterUploadEngine *engine;
        //! @arg Upload queue.
        CReporterUploadQueue queue;
        //! @arg Is the service active.
        bool activated;
        //! @arg files that have been added to upload queue during this auto uploader session
        QStringList addedFiles;
        /*! Notification object giving user a notice that upload is in progress.*/
        CReporterNotification *progressNotification;
        /*! Notification object giving user a notice of successful uploads.*/
        CReporterNotification *successNotification;
        /*! Notification object giving user a notice of failed uploads.*/
        CReporterNotification *failedNotification;

};

CReporterAutoUploader::CReporterAutoUploader() : d_ptr(new CReporterAutoUploaderPrivate)
{
    d_ptr->engine = 0;
    d_ptr->activated = false;
    d_ptr->progressNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
            0, this);
    d_ptr->successNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
                    CReporterSavedState::instance()->uploadSuccessNotificationId(),
                    this);
    d_ptr->failedNotification =
            new CReporterNotification(CReporter::AutoUploaderNotificationEventType,
                    CReporterSavedState::instance()->uploadFailedNotificationId(),
                    this);

    // Create adaptor class. Needs to be taken from the stack.
    new AutoUploaderAdaptor(this);
    // Register service name and object.
    QDBusConnection::sessionBus().registerService(CReporter::AutoUploaderServiceName);
    QDBusConnection::sessionBus().registerObject(CReporter::AutoUploaderObjectPath, this);
    qDebug() << __PRETTY_FUNCTION__ << "Started Auto Uploader service.";
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::~CReporterAutoUploader
// ----------------------------------------------------------------------------
CReporterAutoUploader::~CReporterAutoUploader()
{
    quit();
    if (d_ptr)
    {
        delete d_ptr;
        d_ptr = 0;
    }

    CReporterSavedState::freeSingleton();

    qDebug() << __PRETTY_FUNCTION__ << "Service closed.";

}

bool CReporterAutoUploader::uploadFiles(const QStringList &fileList,
        bool obeyNetworkRestrictions)
{
    qDebug() << __PRETTY_FUNCTION__ << "Received a list of files to upload.";

    if (fileList.isEmpty())
        return false;

    if (!d_ptr->activated)
    {
        d_ptr->engine = new CReporterUploadEngine(&d_ptr->queue);
        d_ptr->activated = true;
        connect(d_ptr->engine, SIGNAL(finished(int, int, int)), SLOT(engineFinished(int, int, int)));
    }

    if (obeyNetworkRestrictions &&
        !CReporterNwSessionMgr::canUseNetworkConnection()) {
        qDebug() << __PRETTY_FUNCTION__
                 << "No unpaid network connection available, aborting crash report upload.";
        QTimer::singleShot(0, this, SLOT(quit()));
        return false;
    }

    foreach (QString filename, fileList)
    {
        if (!d_ptr->addedFiles.contains(filename))
        {
            qDebug() << __PRETTY_FUNCTION__ << "Adding to upload queue: " << filename;
            // CReporterUploadQueue class will own the CReporterUploadItem instance.
            d_ptr->queue.enqueue(new CReporterUploadItem(filename));
            d_ptr->addedFiles << filename;
        }
        else
        {
            qDebug() << __PRETTY_FUNCTION__ << filename << "was not added to queue because it had already been added before";
        }
    }

    if (CReporterPrivacySettingsModel::instance()->notificationsEnabled())
    {
        d_ptr->progressNotification->update(
                //% "Uploading reports"
                qtTrId("crash_reporter-notify-uploading_reports"),
                //% "%1 report(s) to upload"
                qtTrId("crash_reporter-notify-num_to_upload").arg(fileList.count()));
    }

    return true;
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::quit
// ----------------------------------------------------------------------------
void CReporterAutoUploader::quit()
{
    qDebug() << __PRETTY_FUNCTION__ << "Quit auto uploader.";
    if (d_ptr->engine)
    {
        if (d_ptr->activated)
        {
            qDebug() << __PRETTY_FUNCTION__ << "Engine active -> cancelling";
            d_ptr->activated = false;
            d_ptr->engine->cancelAll();
        }
        qDebug() << __PRETTY_FUNCTION__ << "Deleting engine.";
        disconnect(d_ptr->engine, SIGNAL(finished(int, int, int)), this, SLOT(engineFinished(int, int, int)));
        d_ptr->engine->deleteLater();
        d_ptr->engine = 0;
    }
    qApp->quit();
}

// ----------------------------------------------------------------------------
// CReporterAutoUploader::engineFinished
// ----------------------------------------------------------------------------
void CReporterAutoUploader::engineFinished(int error, int sent, int total)
{
    QString message;

    // Construct message.
    switch (error)
    {
        case CReporterUploadEngine::NoError:
            //% "%1 report(s) uploaded successfully."
            message = qtTrId("qtn_%1_crash_reports_uploaded_successfully_text").arg(total);
            break;
        case CReporterUploadEngine::ProtocolError:
        case CReporterUploadEngine::ConnectionNotAvailable:
        case CReporterUploadEngine::ConnectionClosed:
            //% "Failed to upload report(s)."
            message = qtTrId("qtn_failed_to_send_crash_reports_text");
            //% "
Upload results: %1 files attempted %2 files succeeded."
            message += qtTrId("qtn_%1_files_attempted_%2_files_succeeded_text").arg(total).arg(sent);
            break;
        default:
        // We should never enter here.
        break;
    };

    if (error != CReporterUploadEngine::NoError)
    {
        // Add error reason.
        if (error == CReporterUploadEngine::ConnectionNotAvailable)
        {
            //% "
Reason: Failed to create internet connection."
            message += qtTrId("qtn_reason_failed_to_create_internet_connection_text");
        }
        else
        {
            QString reason = d_ptr->engine->lastError();
            if (!reason.isEmpty())
            {
                // If reason is available, append it.
                //% "
Reason: %1."
                message += qtTrId("qtn_reason_%1_text").arg(reason);
            }
            else
            {
                // Use default error.
                //% "
Reason: Unknown."
                message += qtTrId("qtn_reason_unknown_text");
            }
        }
    }

    if (CReporterPrivacySettingsModel::instance()->notificationsEnabled()) {
        d_ptr->progressNotification->remove();

        if (total > sent) {
            int failures = total - sent;
            d_ptr->failedNotification->update(
                    //% "Failed to send all reports"
                    qtTrId("crash_reporter-notify-send_failed"),
                    //% "%1 uploads failed"
                    qtTrId("crash_reporter-notify-num_failed").arg(failures),
                    failures);
        } else {
            d_ptr->failedNotification->remove();
        }

        CReporterSavedState *state = CReporterSavedState::instance();

        if (sent > 0) {
            sent += state->uploadSuccessCount();

            //% "Report uploaded"
            QString summary = (sent == 1) ? qtTrId("crash_reporter-notify-report_uploaded")
                                          : //% "Reports uploaded"
                                            qtTrId("crash_reporter-notify-reports_uploaded");
            d_ptr->successNotification->update(summary, QString(), sent);
        }

        state->setUploadSuccessNotificationId(d_ptr->successNotification->id());
        state->setUploadFailedNotificationId(d_ptr->failedNotification->id());
        state->setUploadSuccessCount(sent);
    }

    qDebug() << __PRETTY_FUNCTION__ << "Message: " << message;

    d_ptr->activated = false;
    quit();
}

#include "moc_autouploader_adaptor.cpp"
<|endoftext|>


<commit_before>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "Stack.hpp"
#include "RefWorkloadUtils.hpp"

namespace armnn
{

void Stack(const StackQueueDescriptor& data,
           std::vector<std::unique_ptr<Decoder<float>>>& inputs,
           Encoder<float>& output,
           const TensorInfo& inputInfo,
           const TensorInfo& outputInfo)
{
    unsigned int outputNumDims = outputInfo.GetNumDimensions();
    unsigned int inputNumDims = inputInfo.GetNumDimensions();

    const armnn::TensorShape& outputDims = outputInfo.GetShape();
    const armnn::TensorShape& inputDims = inputInfo.GetShape();

    unsigned int axis = data.m_Parameters.m_Axis;

    // Can perform a simple concatenation when axis == 0
    if (!axis)
    {
        unsigned int numInputs = data.m_Parameters.m_NumInputs;
        unsigned int inputLength = inputInfo.GetNumElements();

        for (unsigned int inputIdx=0; inputIdx<numInputs; ++inputIdx)
        {
            for (unsigned int elmt=0; elmt<inputLength; ++elmt)
            {
                (*inputs[inputIdx])[elmt];
                output[(inputIdx * inputLength) + elmt];
                output.Set(inputs[inputIdx]->Get());
            }
        }
        return;
    }

    // Initialise output data
    unsigned int numOutputElements = 1;
    for (unsigned int i=0; i<outputNumDims; ++i)
    {
        numOutputElements *= outputDims[i];
    }

    const unsigned int iNumTensors = static_cast<unsigned int>(data.m_Inputs.size());
    const unsigned int iBatchSize  = inputDims[0];
    const unsigned int iChannels   = (inputNumDims > 1) ? inputDims[1] : 1;
    const unsigned int iHeight     = (inputNumDims > 2) ? inputDims[2] : 1;
    const unsigned int iWidth      = (inputNumDims > 3) ? inputDims[3] : 1;

    const unsigned int oBatchSize  = outputDims[1];
    const unsigned int oChannels   = (outputNumDims > 2) ? outputDims[2] : 1;
    const unsigned int oHeight     = (outputNumDims > 3) ? outputDims[3] : 1;
    const unsigned int oWidth      = (outputNumDims > 4) ? outputDims[4] : 1;

    // Array to store the input coordinates
    // iCoordinates[0] = i, iCoordinates[1] = bi, iCoordinates[2] = ci
    // iCoordinates[3] = hi, iCoordinates[4] = wi, iCoordinates[5] = 0
    // iCoordinates[5] will be always zero and used for not incrementing
    // the output when the input has less than 4 dimensions
    std::array<unsigned int, 6> iCoordinates{ 0 };

    // Array of pointers used to map the output coordinates to the input ones, in accordance with the axis
    // This array is initialized with &iCoordinates[5] since this will be always zero
    std::array<unsigned int *, 5> oCoordinates = { &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5] };

    // Set the axis coordinate
    oCoordinates[axis] = &iCoordinates[0];

    // Map the output coordinates, accounting for the axis
    unsigned int dim_shift = 0;
    for(unsigned int dim = 0; dim < inputNumDims; ++dim)
    {
        if(dim == axis)
        {
            dim_shift++;
        }
        oCoordinates[dim + dim_shift] = &iCoordinates[dim + 1];
    }

    // Alias for the input coordinates
    unsigned int &i  = iCoordinates[0];
    unsigned int &bi = iCoordinates[1];
    unsigned int &ci = iCoordinates[2];
    unsigned int &hi = iCoordinates[3];
    unsigned int &wi = iCoordinates[4];

    // Alias for the output coordinates
    unsigned int &o  = *(oCoordinates[0]);
    unsigned int &bo = *(oCoordinates[1]);
    unsigned int &co = *(oCoordinates[2]);
    unsigned int &ho = *(oCoordinates[3]);
    unsigned int &wo = *(oCoordinates[4]);

    // Stack tensors
    for(; i < iNumTensors; ++(i))
    {
        for(bi = 0; bi < iBatchSize; ++(bi))
        {
            for(ci = 0; ci < iChannels; ++(ci))
            {
                for(hi = 0; hi < iHeight; ++(hi))
                {
                    for(wi = 0; wi < iWidth; ++(wi))
                    {
                        output[o  * oWidth * oHeight * oChannels * oBatchSize +
                               bo * oWidth * oHeight * oChannels +
                               co * oWidth * oHeight +
                               ho * oWidth +
                               wo];

                        output.Set(inputs[i]->Get());

                        ++(*(inputs[i]));
                    }
                }
            }
        }
    }
}

} // namespace armnn
<commit_msg>GitHub #634 Remove unused variable from Stack.cpp<commit_after>//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "Stack.hpp"
#include "RefWorkloadUtils.hpp"

namespace armnn
{

void Stack(const StackQueueDescriptor& data,
           std::vector<std::unique_ptr<Decoder<float>>>& inputs,
           Encoder<float>& output,
           const TensorInfo& inputInfo,
           const TensorInfo& outputInfo)
{
    unsigned int outputNumDims = outputInfo.GetNumDimensions();
    unsigned int inputNumDims = inputInfo.GetNumDimensions();

    const armnn::TensorShape& outputDims = outputInfo.GetShape();
    const armnn::TensorShape& inputDims = inputInfo.GetShape();

    unsigned int axis = data.m_Parameters.m_Axis;

    // Can perform a simple concatenation when axis == 0
    if (!axis)
    {
        unsigned int numInputs = data.m_Parameters.m_NumInputs;
        unsigned int inputLength = inputInfo.GetNumElements();

        for (unsigned int inputIdx=0; inputIdx<numInputs; ++inputIdx)
        {
            for (unsigned int elmt=0; elmt<inputLength; ++elmt)
            {
                (*inputs[inputIdx])[elmt];
                output[(inputIdx * inputLength) + elmt];
                output.Set(inputs[inputIdx]->Get());
            }
        }
        return;
    }

    const unsigned int iNumTensors = static_cast<unsigned int>(data.m_Inputs.size());
    const unsigned int iBatchSize  = inputDims[0];
    const unsigned int iChannels   = (inputNumDims > 1) ? inputDims[1] : 1;
    const unsigned int iHeight     = (inputNumDims > 2) ? inputDims[2] : 1;
    const unsigned int iWidth      = (inputNumDims > 3) ? inputDims[3] : 1;

    const unsigned int oBatchSize  = outputDims[1];
    const unsigned int oChannels   = (outputNumDims > 2) ? outputDims[2] : 1;
    const unsigned int oHeight     = (outputNumDims > 3) ? outputDims[3] : 1;
    const unsigned int oWidth      = (outputNumDims > 4) ? outputDims[4] : 1;

    // Array to store the input coordinates
    // iCoordinates[0] = i, iCoordinates[1] = bi, iCoordinates[2] = ci
    // iCoordinates[3] = hi, iCoordinates[4] = wi, iCoordinates[5] = 0
    // iCoordinates[5] will be always zero and used for not incrementing
    // the output when the input has less than 4 dimensions
    std::array<unsigned int, 6> iCoordinates{ 0 };

    // Array of pointers used to map the output coordinates to the input ones, in accordance with the axis
    // This array is initialized with &iCoordinates[5] since this will be always zero
    std::array<unsigned int *, 5> oCoordinates = { &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5],
                                                   &iCoordinates[5] };

    // Set the axis coordinate
    oCoordinates[axis] = &iCoordinates[0];

    // Map the output coordinates, accounting for the axis
    unsigned int dim_shift = 0;
    for(unsigned int dim = 0; dim < inputNumDims; ++dim)
    {
        if(dim == axis)
        {
            dim_shift++;
        }
        oCoordinates[dim + dim_shift] = &iCoordinates[dim + 1];
    }

    // Alias for the input coordinates
    unsigned int &i  = iCoordinates[0];
    unsigned int &bi = iCoordinates[1];
    unsigned int &ci = iCoordinates[2];
    unsigned int &hi = iCoordinates[3];
    unsigned int &wi = iCoordinates[4];

    // Alias for the output coordinates
    unsigned int &o  = *(oCoordinates[0]);
    unsigned int &bo = *(oCoordinates[1]);
    unsigned int &co = *(oCoordinates[2]);
    unsigned int &ho = *(oCoordinates[3]);
    unsigned int &wo = *(oCoordinates[4]);

    // Stack tensors
    for(; i < iNumTensors; ++(i))
    {
        for(bi = 0; bi < iBatchSize; ++(bi))
        {
            for(ci = 0; ci < iChannels; ++(ci))
            {
                for(hi = 0; hi < iHeight; ++(hi))
                {
                    for(wi = 0; wi < iWidth; ++(wi))
                    {
                        output[o  * oWidth * oHeight * oChannels * oBatchSize +
                               bo * oWidth * oHeight * oChannels +
                               co * oWidth * oHeight +
                               ho * oWidth +
                               wo];

                        output.Set(inputs[i]->Get());

                        ++(*(inputs[i]));
                    }
                }
            }
        }
    }
}

} // namespace armnn
<|endoftext|>


<commit_before>#include "buzz_qt_statetree_model.h"
#include "buzz_qt_statetree_item.h"

#include <argos3/core/utility/logging/argos_log.h>

using namespace argos;

/****************************************/
/****************************************/

CBuzzQTStateTreeModel::CBuzzQTStateTreeModel(buzzvm_t pt_state,
                                             bool b_remove_empty_tables,
                                             QObject* pc_parent) :
   QAbstractItemModel(pc_parent),
   m_bRemoveEmptyTables(b_remove_empty_tables),
   m_ptState(pt_state) {
   m_pcDataRoot = new CBuzzQTStateTreeItem();
}

/****************************************/
/****************************************/

CBuzzQTStateTreeModel::~CBuzzQTStateTreeModel() {
   delete m_pcDataRoot;
}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeModel::data(const QModelIndex& c_index,
                                     int n_role) const {
   if(!c_index.isValid()) return QVariant();
   if(n_role != Qt::DisplayRole) return QVariant();
   CBuzzQTStateTreeItem* pcItem = static_cast<CBuzzQTStateTreeItem*>(c_index.internalPointer());
   return pcItem->GetData(c_index.column());
}

/****************************************/
/****************************************/

Qt::ItemFlags CBuzzQTStateTreeModel::flags(const QModelIndex& c_index) const {
   if (!c_index.isValid()) return 0;
   else return Qt::ItemIsEnabled;
}

/****************************************/
/****************************************/

QModelIndex CBuzzQTStateTreeModel::index(int n_row,
                                         int n_column,
                                         const QModelIndex& c_parent) const {
   if(!hasIndex(n_row, n_column, c_parent)) return QModelIndex();
   CBuzzQTStateTreeItem* pcParentItem;
   if(!c_parent.isValid()) pcParentItem = m_pcDataRoot;
   else pcParentItem = static_cast<CBuzzQTStateTreeItem*>(c_parent.internalPointer());
   CBuzzQTStateTreeItem* pcChildItem = pcParentItem->GetChild(n_row);
   if(pcChildItem) return createIndex(n_row, n_column, pcChildItem);
   else return QModelIndex();
}

/****************************************/
/****************************************/

QModelIndex CBuzzQTStateTreeModel::parent(const QModelIndex& c_index) const {
   if (!c_index.isValid()) return QModelIndex();
   CBuzzQTStateTreeItem* pcChildItem = static_cast<CBuzzQTStateTreeItem*>(c_index.internalPointer());
   CBuzzQTStateTreeItem* pcParentItem = pcChildItem->GetParent();
   if (pcParentItem == m_pcDataRoot) return QModelIndex();
   else return createIndex(pcParentItem->GetRow(), 0, pcParentItem);
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeModel::rowCount(const QModelIndex& c_parent) const {
   CBuzzQTStateTreeItem* pcParentItem;
   if(c_parent.column() > 0) return 0;
   if(!c_parent.isValid()) pcParentItem = m_pcDataRoot;
   else pcParentItem = static_cast<CBuzzQTStateTreeItem*>(c_parent.internalPointer());
   return pcParentItem->GetNumChildren();
}

/****************************************/
/****************************************/

void CBuzzQTStateTreeModel::SetBuzzState(buzzvm_t pt_state) {
   m_ptState = pt_state;
   Refresh();
}

/****************************************/
/****************************************/

struct SBuzzProcessStateData {
   buzzvm_t VM;
   CBuzzQTStateTreeItem* Item;
   bool NoEmptyTables;
};

void CBuzzQTStateTreeModel::Refresh() {
   beginResetModel();
   delete m_pcDataRoot;
   m_pcDataRoot = new CBuzzQTStateTreeItem();
   ProcessBuzzState(m_ptState, m_pcDataRoot);
   m_pcDataRoot->SortChildren();
   endResetModel();
}

void CBuzzQTStateTreeModel::Refresh(int) {
   Refresh();
}

/****************************************/
/****************************************/

CBuzzQTStateTreeVariableModel::CBuzzQTStateTreeVariableModel(buzzvm_t pt_state,
                                                             bool b_remove_empty_tables,
                                                             QObject* pc_parent) :
   CBuzzQTStateTreeModel(pt_state, b_remove_empty_tables, pc_parent) {}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeVariableModel::headerData(int n_section,
                                                   Qt::Orientation e_orientation,
                                                   int n_role) const {
   if(e_orientation != Qt::Horizontal ||
      n_role != Qt::DisplayRole ||
      n_section > 1) {
      return QVariant();
   }
   else {
      return n_section == 0 ? tr("Variable") : tr("Value");
   }
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeVariableModel::columnCount(const QModelIndex&) const {
   return 2;
}

/****************************************/
/****************************************/

void ProcessBuzzObjectsInTable(const void* pt_key,
                               void* pt_data,
                               void* pt_params) {
   /* Get the key */
   const buzzobj_t tKey = *reinterpret_cast<const buzzobj_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   switch(tKey->o.type) {
      case BUZZTYPE_INT:
         cData << tKey->i.value;
         break;
      case BUZZTYPE_FLOAT:
         cData << tKey->f.value;
         break;
      case BUZZTYPE_STRING:
         cData << tKey->s.value.str;
         break;
      default:
         return;
   }
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      /* Insert key data */
      switch(tData->o.type) {
         case BUZZTYPE_INT:
            cData << tData->i.value;
            break;
         case BUZZTYPE_FLOAT:
            cData << tData->f.value;
            break;
         case BUZZTYPE_STRING:
            cData << tData->s.value.str;
            break;
         case BUZZTYPE_USERDATA:
            cData << "[userdata]";
            break;
         default:
            return;
      }
      psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzObjectsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0) {
            psParams->Item->RemoveChild(pcChild);
         }
      }
   }
}

void ProcessBuzzObjects(const void* pt_key,
                        void* pt_data,
                        void* pt_params) {
   /* Get the key as a string */
   uint16_t unKeyId = *reinterpret_cast<const uint16_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   cData << buzzvm_string_get(psParams->VM, unKeyId);
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      /* Insert value data */
      switch(tData->o.type) {
         case BUZZTYPE_INT:
            cData << tData->i.value;
            break;
         case BUZZTYPE_FLOAT:
            cData << tData->f.value;
            break;
         case BUZZTYPE_STRING:
            cData << tData->s.value.str;
            break;
         case BUZZTYPE_USERDATA:
            cData << "[userdata]";
            break;
         default:
            return;
      }
      psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzObjectsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0) {
            psParams->Item->RemoveChild(pcChild);
         }
      }
   }
}

void CBuzzQTStateTreeVariableModel::ProcessBuzzState(buzzvm_t pt_state,
                                                     CBuzzQTStateTreeItem* pc_item) {
   SBuzzProcessStateData sParams = {
      .VM = pt_state,
      .Item = pc_item,
      .NoEmptyTables = m_bRemoveEmptyTables
   };
   buzzdict_foreach(pt_state->gsyms, ProcessBuzzObjects, &sParams);
}

/****************************************/
/****************************************/

CBuzzQTStateTreeFunctionModel::CBuzzQTStateTreeFunctionModel(buzzvm_t pt_state,
                                                             bool b_remove_empty_tables,
                                                             QObject* pc_parent) :
   CBuzzQTStateTreeModel(pt_state, b_remove_empty_tables, pc_parent) {}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeFunctionModel::headerData(int n_section,
                                                   Qt::Orientation e_orientation,
                                                   int n_role) const {
   return QVariant();
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeFunctionModel::columnCount(const QModelIndex&) const {
   return 1;
}

/****************************************/
/****************************************/

void ProcessBuzzFunctionsInTable(const void* pt_key,
                                 void* pt_data,
                                 void* pt_params) {
   /* Get the key */
   buzzobj_t tKey = *reinterpret_cast<const buzzobj_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   if(tKey->o.type == BUZZTYPE_STRING) {
      cData << tKey->s.value.str;
   }
   else {
      return;
   }
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      if(tData->o.type == BUZZTYPE_CLOSURE) {
         cData[0] = cData[0].toString() + "()";
         psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
      }
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzFunctionsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0)
            psParams->Item->RemoveChild(pcChild);
      }
   }
}

void ProcessBuzzFunctions(const void* pt_key,
                          void* pt_data,
                          void* pt_params) {
   /* Get the key */
   uint16_t unKeyId = *reinterpret_cast<const uint16_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   cData << buzzvm_string_get(psParams->VM, unKeyId);
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      if(tData->o.type == BUZZTYPE_CLOSURE) {
         cData[0] = cData[0].toString() + "()";
         psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
      }
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzFunctionsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0)
            psParams->Item->RemoveChild(pcChild);
      }
   }
}

void CBuzzQTStateTreeFunctionModel::ProcessBuzzState(buzzvm_t pt_state,
                                                     CBuzzQTStateTreeItem* pc_item) {
   SBuzzProcessStateData sParams = {
      .VM = pt_state,
      .Item = pc_item,
      .NoEmptyTables = m_bRemoveEmptyTables
   };
   buzzdict_foreach(pt_state->gsyms, ProcessBuzzFunctions, &sParams);
}

/****************************************/
/****************************************/
<commit_msg>Added quotes in qt state tree model for strings.<commit_after>#include "buzz_qt_statetree_model.h"
#include "buzz_qt_statetree_item.h"

#include <argos3/core/utility/logging/argos_log.h>

using namespace argos;

/****************************************/
/****************************************/

CBuzzQTStateTreeModel::CBuzzQTStateTreeModel(buzzvm_t pt_state,
                                             bool b_remove_empty_tables,
                                             QObject* pc_parent) :
   QAbstractItemModel(pc_parent),
   m_bRemoveEmptyTables(b_remove_empty_tables),
   m_ptState(pt_state) {
   m_pcDataRoot = new CBuzzQTStateTreeItem();
}

/****************************************/
/****************************************/

CBuzzQTStateTreeModel::~CBuzzQTStateTreeModel() {
   delete m_pcDataRoot;
}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeModel::data(const QModelIndex& c_index,
                                     int n_role) const {
   if(!c_index.isValid()) return QVariant();
   if(n_role != Qt::DisplayRole) return QVariant();
   CBuzzQTStateTreeItem* pcItem = static_cast<CBuzzQTStateTreeItem*>(c_index.internalPointer());
   return pcItem->GetData(c_index.column());
}

/****************************************/
/****************************************/

Qt::ItemFlags CBuzzQTStateTreeModel::flags(const QModelIndex& c_index) const {
   if (!c_index.isValid()) return 0;
   else return Qt::ItemIsEnabled;
}

/****************************************/
/****************************************/

QModelIndex CBuzzQTStateTreeModel::index(int n_row,
                                         int n_column,
                                         const QModelIndex& c_parent) const {
   if(!hasIndex(n_row, n_column, c_parent)) return QModelIndex();
   CBuzzQTStateTreeItem* pcParentItem;
   if(!c_parent.isValid()) pcParentItem = m_pcDataRoot;
   else pcParentItem = static_cast<CBuzzQTStateTreeItem*>(c_parent.internalPointer());
   CBuzzQTStateTreeItem* pcChildItem = pcParentItem->GetChild(n_row);
   if(pcChildItem) return createIndex(n_row, n_column, pcChildItem);
   else return QModelIndex();
}

/****************************************/
/****************************************/

QModelIndex CBuzzQTStateTreeModel::parent(const QModelIndex& c_index) const {
   if (!c_index.isValid()) return QModelIndex();
   CBuzzQTStateTreeItem* pcChildItem = static_cast<CBuzzQTStateTreeItem*>(c_index.internalPointer());
   CBuzzQTStateTreeItem* pcParentItem = pcChildItem->GetParent();
   if (pcParentItem == m_pcDataRoot) return QModelIndex();
   else return createIndex(pcParentItem->GetRow(), 0, pcParentItem);
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeModel::rowCount(const QModelIndex& c_parent) const {
   CBuzzQTStateTreeItem* pcParentItem;
   if(c_parent.column() > 0) return 0;
   if(!c_parent.isValid()) pcParentItem = m_pcDataRoot;
   else pcParentItem = static_cast<CBuzzQTStateTreeItem*>(c_parent.internalPointer());
   return pcParentItem->GetNumChildren();
}

/****************************************/
/****************************************/

void CBuzzQTStateTreeModel::SetBuzzState(buzzvm_t pt_state) {
   m_ptState = pt_state;
   Refresh();
}

/****************************************/
/****************************************/

struct SBuzzProcessStateData {
   buzzvm_t VM;
   CBuzzQTStateTreeItem* Item;
   bool NoEmptyTables;
};

void CBuzzQTStateTreeModel::Refresh() {
   beginResetModel();
   delete m_pcDataRoot;
   m_pcDataRoot = new CBuzzQTStateTreeItem();
   ProcessBuzzState(m_ptState, m_pcDataRoot);
   m_pcDataRoot->SortChildren();
   endResetModel();
}

void CBuzzQTStateTreeModel::Refresh(int) {
   Refresh();
}

/****************************************/
/****************************************/

CBuzzQTStateTreeVariableModel::CBuzzQTStateTreeVariableModel(buzzvm_t pt_state,
                                                             bool b_remove_empty_tables,
                                                             QObject* pc_parent) :
   CBuzzQTStateTreeModel(pt_state, b_remove_empty_tables, pc_parent) {}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeVariableModel::headerData(int n_section,
                                                   Qt::Orientation e_orientation,
                                                   int n_role) const {
   if(e_orientation != Qt::Horizontal ||
      n_role != Qt::DisplayRole ||
      n_section > 1) {
      return QVariant();
   }
   else {
      return n_section == 0 ? tr("Variable") : tr("Value");
   }
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeVariableModel::columnCount(const QModelIndex&) const {
   return 2;
}

/****************************************/
/****************************************/

void ProcessBuzzObjectsInTable(const void* pt_key,
                               void* pt_data,
                               void* pt_params) {
   /* Get the key */
   const buzzobj_t tKey = *reinterpret_cast<const buzzobj_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   switch(tKey->o.type) {
      case BUZZTYPE_INT:
         cData << tKey->i.value;
         break;
      case BUZZTYPE_FLOAT:
         cData << tKey->f.value;
         break;
      case BUZZTYPE_STRING:
         cData << tKey->s.value.str;
         break;
      default:
         return;
   }
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      /* Insert key data */
      switch(tData->o.type) {
         case BUZZTYPE_INT:
            cData << tData->i.value;
            break;
         case BUZZTYPE_FLOAT:
            cData << tData->f.value;
            break;
         case BUZZTYPE_STRING:
            cData << QString("\"%1\"").arg(tData->s.value.str);
            break;
         case BUZZTYPE_USERDATA:
            cData << "[userdata]";
            break;
         default:
            return;
      }
      psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzObjectsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0) {
            psParams->Item->RemoveChild(pcChild);
         }
      }
   }
}

void ProcessBuzzObjects(const void* pt_key,
                        void* pt_data,
                        void* pt_params) {
   /* Get the key as a string */
   uint16_t unKeyId = *reinterpret_cast<const uint16_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   cData << buzzvm_string_get(psParams->VM, unKeyId);
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      /* Insert value data */
      switch(tData->o.type) {
         case BUZZTYPE_INT:
            cData << tData->i.value;
            break;
         case BUZZTYPE_FLOAT:
            cData << tData->f.value;
            break;
         case BUZZTYPE_STRING:
            cData << QString("\"%1\"").arg(tData->s.value.str);
            break;
         case BUZZTYPE_USERDATA:
            cData << "[userdata]";
            break;
         default:
            return;
      }
      psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzObjectsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0) {
            psParams->Item->RemoveChild(pcChild);
         }
      }
   }
}

void CBuzzQTStateTreeVariableModel::ProcessBuzzState(buzzvm_t pt_state,
                                                     CBuzzQTStateTreeItem* pc_item) {
   SBuzzProcessStateData sParams = {
      .VM = pt_state,
      .Item = pc_item,
      .NoEmptyTables = m_bRemoveEmptyTables
   };
   buzzdict_foreach(pt_state->gsyms, ProcessBuzzObjects, &sParams);
}

/****************************************/
/****************************************/

CBuzzQTStateTreeFunctionModel::CBuzzQTStateTreeFunctionModel(buzzvm_t pt_state,
                                                             bool b_remove_empty_tables,
                                                             QObject* pc_parent) :
   CBuzzQTStateTreeModel(pt_state, b_remove_empty_tables, pc_parent) {}

/****************************************/
/****************************************/

QVariant CBuzzQTStateTreeFunctionModel::headerData(int n_section,
                                                   Qt::Orientation e_orientation,
                                                   int n_role) const {
   return QVariant();
}

/****************************************/
/****************************************/

int CBuzzQTStateTreeFunctionModel::columnCount(const QModelIndex&) const {
   return 1;
}

/****************************************/
/****************************************/

void ProcessBuzzFunctionsInTable(const void* pt_key,
                                 void* pt_data,
                                 void* pt_params) {
   /* Get the key */
   buzzobj_t tKey = *reinterpret_cast<const buzzobj_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   if(tKey->o.type == BUZZTYPE_STRING) {
      cData << tKey->s.value.str;
   }
   else {
      return;
   }
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      if(tData->o.type == BUZZTYPE_CLOSURE) {
         cData[0] = cData[0].toString() + "()";
         psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
      }
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzFunctionsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0)
            psParams->Item->RemoveChild(pcChild);
      }
   }
}

void ProcessBuzzFunctions(const void* pt_key,
                          void* pt_data,
                          void* pt_params) {
   /* Get the key */
   uint16_t unKeyId = *reinterpret_cast<const uint16_t*>(pt_key);
   /* Get the data */
   buzzobj_t tData = *reinterpret_cast<buzzobj_t*>(pt_data);
   /* Get the parameters */
   SBuzzProcessStateData* psParams = reinterpret_cast<SBuzzProcessStateData*>(pt_params);
   /* Buffer for element */
   QList<QVariant> cData;
   /* Insert key data */
   cData << buzzvm_string_get(psParams->VM, unKeyId);
   /* Insert value data */
   if(tData->o.type != BUZZTYPE_TABLE) {
      /* Non-table data type */
      if(tData->o.type == BUZZTYPE_CLOSURE) {
         cData[0] = cData[0].toString() + "()";
         psParams->Item->AddChild(new CBuzzQTStateTreeItem(cData, psParams->Item));
      }
   }
   else {
      /* Table data type */
      /* Add new child to tree */
      CBuzzQTStateTreeItem* pcChild = new CBuzzQTStateTreeItem(cData, psParams->Item);
      psParams->Item->AddChild(pcChild);
      /* Process the element of the child */
      SBuzzProcessStateData sParams2 = {
         .VM = psParams->VM,
         .Item = pcChild,
         .NoEmptyTables = psParams->NoEmptyTables
      };
      buzzdict_foreach(tData->t.value, ProcessBuzzFunctionsInTable, &sParams2);
      /* If no elements were added, remove the child */
      if(psParams->NoEmptyTables) {
         if(pcChild->GetNumChildren() == 0)
            psParams->Item->RemoveChild(pcChild);
      }
   }
}

void CBuzzQTStateTreeFunctionModel::ProcessBuzzState(buzzvm_t pt_state,
                                                     CBuzzQTStateTreeItem* pc_item) {
   SBuzzProcessStateData sParams = {
      .VM = pt_state,
      .Item = pc_item,
      .NoEmptyTables = m_bRemoveEmptyTables
   };
   buzzdict_foreach(pt_state->gsyms, ProcessBuzzFunctions, &sParams);
}

/****************************************/
/****************************************/
<|endoftext|>