<commit_before>/*
 * Copyright 2015 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.
 */

#include "accumulatedtracedata.h"

#include <iostream>
#include <memory>
#include <algorithm>
#include <cassert>

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

#include "linereader.h"
#include "config.h"
#include "pointermap.h"

using namespace std;

namespace {

template<typename Base>
bool operator>>(LineReader& reader, Index<Base> &index)
{
    return reader.readHex(index.index);
}

template<typename Base>
ostream& operator<<(ostream &out, const Index<Base> index)
{
    out << index.index;
    return out;
}

}

AccumulatedTraceData::AccumulatedTraceData()
{
    instructionPointers.reserve(16384);
    traces.reserve(65536);
    strings.reserve(4096);
    allocations.reserve(16384);
    stopIndices.reserve(4);
    opNewIpIndices.reserve(16);
}

const string& AccumulatedTraceData::stringify(const StringIndex stringId) const
{
    if (!stringId || stringId.index > strings.size()) {
        static const string empty;
        return empty;
    } else {
        return strings.at(stringId.index - 1);
    }
}

string AccumulatedTraceData::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 == '<' || c == '>') && ret.size() >= 8) {
            // don't get confused by C++ operators
            const char* cmp = "operator";
            if (ret.back() == c) {
                // skip second angle bracket for operator<< or operator>>
                if (c == '<') {
                    cmp = "operator<";
                } else {
                    cmp = "operator>";
                }
            }
            if (boost::algorithm::ends_with(ret, cmp)) {
                ret.push_back(c);
                continue;
            }
        }
        if (c == '<') {
            ++depth;
            if (depth == 1) {
                ret.push_back(c);
            }
        } else if (c == '>') {
            --depth;
        }
        if (depth) {
            continue;
        }
        ret.push_back(c);
    }
    return ret;
}

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

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

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

bool AccumulatedTraceData::read(istream& in)
{
    LineReader reader;
    uint64_t timeStamp = 0;

    vector<StringIndex> opNewStrIndices;
    opNewStrIndices.reserve(16);
    vector<string> opNewStrings = {
        "operator new(unsigned long)",
        "operator new[](unsigned long)"
    };

    vector<string> stopStrings = {
        "main",
        "__libc_start_main",
        "__static_initialization_and_destruction_0"
    };

    const bool reparsing = totalTime != 0;
    m_maxAllocationTraceIndex.index = 0;
    totalAllocated = 0;
    totalAllocations = 0;
    totalTemporary = 0;
    peak = 0;
    peakTime = 0;
    leaked = 0;
    systemInfo = {};
    peakRSS = 0;
    allocations.clear();
    uint fileVersion = 0;

    // required for backwards compatibility
    // newer versions handle this in heaptrack_interpret already
    AllocationInfoSet allocationInfoSet;
    PointerMap pointers;
    uint64_t lastAllocationPtr = 0;

    while (reader.getLine(in)) {
        if (reader.mode() == 's') {
            if (reparsing) {
                continue;
            }
            strings.push_back(reader.line().substr(2));
            StringIndex index;
            index.index = strings.size();

            auto opNewIt = find(opNewStrings.begin(), opNewStrings.end(), strings.back());
            if (opNewIt != opNewStrings.end()) {
                opNewStrIndices.push_back(index);
                opNewStrings.erase(opNewIt);
            } else {
                auto stopIt = find(stopStrings.begin(), stopStrings.end(), strings.back());
                if (stopIt != stopStrings.end()) {
                    stopIndices.push_back(index);
                    stopStrings.erase(stopIt);
                }
            }
        } else if (reader.mode() == 't') {
            if (reparsing) {
                continue;
            }
            TraceNode node;
            reader >> node.ipIndex;
            reader >> node.parentIndex;
            // skip operator new and operator new[] at the beginning of traces
            while (find(opNewIpIndices.begin(), opNewIpIndices.end(), node.ipIndex) != opNewIpIndices.end()) {
                node = findTrace(node.parentIndex);
            }
            traces.push_back(node);
        } else if (reader.mode() == 'i') {
            if (reparsing) {
                continue;
            }
            InstructionPointer ip;
            reader >> ip.instructionPointer;
            reader >> ip.moduleIndex;
            reader >> ip.functionIndex;
            reader >> ip.fileIndex;
            reader >> ip.line;
            instructionPointers.push_back(ip);
            if (find(opNewStrIndices.begin(), opNewStrIndices.end(), ip.functionIndex) != opNewStrIndices.end()) {
                IpIndex index;
                index.index = instructionPointers.size();
                opNewIpIndices.push_back(index);
            }
        } else if (reader.mode() == '+') {
            AllocationInfo info;
            AllocationIndex allocationIndex;
            if (fileVersion >= 0x010000) {
                if (!(reader >> allocationIndex.index)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                info = allocationInfos[allocationIndex.index];
            } else { // backwards compatibility
                uint64_t ptr = 0;
                if (!(reader >> info.size) || !(reader >> info.traceIndex) || !(reader >> ptr)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                if (allocationInfoSet.add(info.size, info.traceIndex, &allocationIndex)) {
                    allocationInfos.push_back(info);
                }
                pointers.addPointer(ptr, allocationIndex);
                lastAllocationPtr = ptr;
            }

            auto& allocation = findAllocation(info.traceIndex);
            allocation.leaked += info.size;
            allocation.allocated += info.size;
            ++allocation.allocations;
            if (allocation.leaked > allocation.peak) {
                allocation.peak = allocation.leaked;
            }

            totalAllocated += info.size;
            ++totalAllocations;
            leaked += info.size;
            if (leaked > peak) {
                peak = leaked;
                peakTime = timeStamp;
            }

            handleAllocation(info, allocationIndex);
        } else if (reader.mode() == '-') {
            AllocationIndex allocationInfoIndex;
            bool temporary = false;
            if (fileVersion >= 0x010000) {
                if (!(reader >> allocationInfoIndex.index)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                // optional, and thus may fail.
                // but that's OK since we default to false anyways
                reader >> temporary;
            } else { // backwards compatibility
                uint64_t ptr = 0;
                if (!(reader >> ptr)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                auto taken = pointers.takePointer(ptr);
                if (!taken.second) {
                    // happens when we attached to a running application
                    continue;
                }
                allocationInfoIndex = taken.first;
                temporary = lastAllocationPtr == ptr;
                lastAllocationPtr = 0;
            }

            const auto& info = allocationInfos[allocationInfoIndex.index];
            auto& allocation = findAllocation(info.traceIndex);
            if (!allocation.allocations || allocation.leaked < info.size) {
                if (!fromAttached) {
                    cerr << "inconsistent allocation info, underflowed allocations of " << info.traceIndex << endl;
                }
                allocation.leaked = 0;
                allocation.allocations = 0;
            } else {
                allocation.leaked -= info.size;
            }
            leaked -= info.size;
            if (temporary) {
                ++allocation.temporary;
                ++totalTemporary;
            }
        } else if (reader.mode() == 'a') {
            if (reparsing) {
                continue;
            }
            AllocationInfo info;
            if (!(reader >> info.size) || !(reader >> info.traceIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                continue;
            }
            allocationInfos.push_back(info);
        } else if (reader.mode() == '#') {
            // comment or empty line
            continue;
        } else if (reader.mode() == 'c') {
            uint64_t newStamp = 0;
            if (!(reader >> newStamp)) {
                cerr << "Failed to read time stamp: " << reader.line() << endl;
                continue;
            }
            handleTimeStamp(timeStamp, newStamp);
            timeStamp = newStamp;
        } else if (reader.mode() == 'R') { // RSS timestamp
            uint64_t rss = 0;
            reader >> rss;
            if (rss > peakRSS) {
                peakRSS = rss;
            }
        } else if (reader.mode() == 'X') {
            handleDebuggee(reader.line().c_str() + 2);
        } else if (reader.mode() == 'A') {
            leaked = 0;
            peak = 0;
            fromAttached = true;
        } else if (reader.mode() == 'v') {
            reader >> fileVersion;
            if (fileVersion > HEAPTRACK_VERSION) {
                cerr << "The data file was written by a newer heaptrack of version " << hex << fileVersion
                     << " and is thus not compatible with this build of heaptrack version " << hex << HEAPTRACK_VERSION << '.' << endl;
                return false;
            }
        } else if (reader.mode() == 'I') { // system information
            reader >> systemInfo.pageSize;
            reader >> systemInfo.pages;
        } else {
            cerr << "failed to parse line: " << reader.line() << endl;
        }
    }

    if (!reparsing) {
        totalTime = timeStamp + 1;
    }

    handleTimeStamp(timeStamp, totalTime);

    return true;
}

Allocation& AccumulatedTraceData::findAllocation(const TraceIndex traceIndex)
{
    if (traceIndex < m_maxAllocationTraceIndex) {
        // only need to search when the trace index is previously known
        auto it = lower_bound(allocations.begin(), allocations.end(), traceIndex,
                            [] (const Allocation& allocation, const TraceIndex traceIndex) -> bool {
                                return allocation.traceIndex < traceIndex;
                            });
        assert(it != allocations.end());
        assert(it->traceIndex == traceIndex);
        return *it;
    } else if (traceIndex == m_maxAllocationTraceIndex && !allocations.empty()) {
        // reuse the last allocation
        assert(allocations.back().traceIndex == traceIndex);
    } else {
        // actually a new allocation
        Allocation allocation;
        allocation.traceIndex = traceIndex;
        allocations.push_back(allocation);
        m_maxAllocationTraceIndex = traceIndex;
    }
    return allocations.back();
}

InstructionPointer AccumulatedTraceData::findIp(const IpIndex ipIndex) const
{
    if (!ipIndex || ipIndex.index > instructionPointers.size()) {
        return {};
    } else {
        return instructionPointers[ipIndex.index - 1];
    }
}

TraceNode AccumulatedTraceData::findTrace(const TraceIndex traceIndex) const
{
    if (!traceIndex || traceIndex.index > traces.size()) {
        return {};
    } else {
        return traces[traceIndex.index - 1];
    }
}

bool AccumulatedTraceData::isStopIndex(const StringIndex index) const
{
    return find(stopIndices.begin(), stopIndices.end(), index) != stopIndices.end();
}
<commit_msg>Properly skip 32bit versions of operator new.<commit_after>/*
 * Copyright 2015 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.
 */

#include "accumulatedtracedata.h"

#include <iostream>
#include <memory>
#include <algorithm>
#include <cassert>

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

#include "linereader.h"
#include "config.h"
#include "pointermap.h"

using namespace std;

namespace {

template<typename Base>
bool operator>>(LineReader& reader, Index<Base> &index)
{
    return reader.readHex(index.index);
}

template<typename Base>
ostream& operator<<(ostream &out, const Index<Base> index)
{
    out << index.index;
    return out;
}

}

AccumulatedTraceData::AccumulatedTraceData()
{
    instructionPointers.reserve(16384);
    traces.reserve(65536);
    strings.reserve(4096);
    allocations.reserve(16384);
    stopIndices.reserve(4);
    opNewIpIndices.reserve(16);
}

const string& AccumulatedTraceData::stringify(const StringIndex stringId) const
{
    if (!stringId || stringId.index > strings.size()) {
        static const string empty;
        return empty;
    } else {
        return strings.at(stringId.index - 1);
    }
}

string AccumulatedTraceData::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 == '<' || c == '>') && ret.size() >= 8) {
            // don't get confused by C++ operators
            const char* cmp = "operator";
            if (ret.back() == c) {
                // skip second angle bracket for operator<< or operator>>
                if (c == '<') {
                    cmp = "operator<";
                } else {
                    cmp = "operator>";
                }
            }
            if (boost::algorithm::ends_with(ret, cmp)) {
                ret.push_back(c);
                continue;
            }
        }
        if (c == '<') {
            ++depth;
            if (depth == 1) {
                ret.push_back(c);
            }
        } else if (c == '>') {
            --depth;
        }
        if (depth) {
            continue;
        }
        ret.push_back(c);
    }
    return ret;
}

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

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

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

bool AccumulatedTraceData::read(istream& in)
{
    LineReader reader;
    uint64_t timeStamp = 0;

    vector<string> opNewStrings = {
        // 64 bit
        "operator new(unsigned long)",
        "operator new[](unsigned long)",
        // 32 bit
        "operator new(unsigned int)",
        "operator new[](unsigned int)",
    };
    vector<StringIndex> opNewStrIndices;
    opNewStrIndices.reserve(opNewStrings.size());

    vector<string> stopStrings = {
        "main",
        "__libc_start_main",
        "__static_initialization_and_destruction_0"
    };

    const bool reparsing = totalTime != 0;
    m_maxAllocationTraceIndex.index = 0;
    totalAllocated = 0;
    totalAllocations = 0;
    totalTemporary = 0;
    peak = 0;
    peakTime = 0;
    leaked = 0;
    systemInfo = {};
    peakRSS = 0;
    allocations.clear();
    uint fileVersion = 0;

    // required for backwards compatibility
    // newer versions handle this in heaptrack_interpret already
    AllocationInfoSet allocationInfoSet;
    PointerMap pointers;
    uint64_t lastAllocationPtr = 0;

    while (reader.getLine(in)) {
        if (reader.mode() == 's') {
            if (reparsing) {
                continue;
            }
            strings.push_back(reader.line().substr(2));
            StringIndex index;
            index.index = strings.size();

            auto opNewIt = find(opNewStrings.begin(), opNewStrings.end(), strings.back());
            if (opNewIt != opNewStrings.end()) {
                opNewStrIndices.push_back(index);
                opNewStrings.erase(opNewIt);
            } else {
                auto stopIt = find(stopStrings.begin(), stopStrings.end(), strings.back());
                if (stopIt != stopStrings.end()) {
                    stopIndices.push_back(index);
                    stopStrings.erase(stopIt);
                }
            }
        } else if (reader.mode() == 't') {
            if (reparsing) {
                continue;
            }
            TraceNode node;
            reader >> node.ipIndex;
            reader >> node.parentIndex;
            // skip operator new and operator new[] at the beginning of traces
            while (find(opNewIpIndices.begin(), opNewIpIndices.end(), node.ipIndex) != opNewIpIndices.end()) {
                node = findTrace(node.parentIndex);
            }
            traces.push_back(node);
        } else if (reader.mode() == 'i') {
            if (reparsing) {
                continue;
            }
            InstructionPointer ip;
            reader >> ip.instructionPointer;
            reader >> ip.moduleIndex;
            reader >> ip.functionIndex;
            reader >> ip.fileIndex;
            reader >> ip.line;
            instructionPointers.push_back(ip);
            if (find(opNewStrIndices.begin(), opNewStrIndices.end(), ip.functionIndex) != opNewStrIndices.end()) {
                IpIndex index;
                index.index = instructionPointers.size();
                opNewIpIndices.push_back(index);
            }
        } else if (reader.mode() == '+') {
            AllocationInfo info;
            AllocationIndex allocationIndex;
            if (fileVersion >= 0x010000) {
                if (!(reader >> allocationIndex.index)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                info = allocationInfos[allocationIndex.index];
            } else { // backwards compatibility
                uint64_t ptr = 0;
                if (!(reader >> info.size) || !(reader >> info.traceIndex) || !(reader >> ptr)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                if (allocationInfoSet.add(info.size, info.traceIndex, &allocationIndex)) {
                    allocationInfos.push_back(info);
                }
                pointers.addPointer(ptr, allocationIndex);
                lastAllocationPtr = ptr;
            }

            auto& allocation = findAllocation(info.traceIndex);
            allocation.leaked += info.size;
            allocation.allocated += info.size;
            ++allocation.allocations;
            if (allocation.leaked > allocation.peak) {
                allocation.peak = allocation.leaked;
            }

            totalAllocated += info.size;
            ++totalAllocations;
            leaked += info.size;
            if (leaked > peak) {
                peak = leaked;
                peakTime = timeStamp;
            }

            handleAllocation(info, allocationIndex);
        } else if (reader.mode() == '-') {
            AllocationIndex allocationInfoIndex;
            bool temporary = false;
            if (fileVersion >= 0x010000) {
                if (!(reader >> allocationInfoIndex.index)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                // optional, and thus may fail.
                // but that's OK since we default to false anyways
                reader >> temporary;
            } else { // backwards compatibility
                uint64_t ptr = 0;
                if (!(reader >> ptr)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    continue;
                }
                auto taken = pointers.takePointer(ptr);
                if (!taken.second) {
                    // happens when we attached to a running application
                    continue;
                }
                allocationInfoIndex = taken.first;
                temporary = lastAllocationPtr == ptr;
                lastAllocationPtr = 0;
            }

            const auto& info = allocationInfos[allocationInfoIndex.index];
            auto& allocation = findAllocation(info.traceIndex);
            if (!allocation.allocations || allocation.leaked < info.size) {
                if (!fromAttached) {
                    cerr << "inconsistent allocation info, underflowed allocations of " << info.traceIndex << endl;
                }
                allocation.leaked = 0;
                allocation.allocations = 0;
            } else {
                allocation.leaked -= info.size;
            }
            leaked -= info.size;
            if (temporary) {
                ++allocation.temporary;
                ++totalTemporary;
            }
        } else if (reader.mode() == 'a') {
            if (reparsing) {
                continue;
            }
            AllocationInfo info;
            if (!(reader >> info.size) || !(reader >> info.traceIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                continue;
            }
            allocationInfos.push_back(info);
        } else if (reader.mode() == '#') {
            // comment or empty line
            continue;
        } else if (reader.mode() == 'c') {
            uint64_t newStamp = 0;
            if (!(reader >> newStamp)) {
                cerr << "Failed to read time stamp: " << reader.line() << endl;
                continue;
            }
            handleTimeStamp(timeStamp, newStamp);
            timeStamp = newStamp;
        } else if (reader.mode() == 'R') { // RSS timestamp
            uint64_t rss = 0;
            reader >> rss;
            if (rss > peakRSS) {
                peakRSS = rss;
            }
        } else if (reader.mode() == 'X') {
            handleDebuggee(reader.line().c_str() + 2);
        } else if (reader.mode() == 'A') {
            leaked = 0;
            peak = 0;
            fromAttached = true;
        } else if (reader.mode() == 'v') {
            reader >> fileVersion;
            if (fileVersion > HEAPTRACK_VERSION) {
                cerr << "The data file was written by a newer heaptrack of version " << hex << fileVersion
                     << " and is thus not compatible with this build of heaptrack version " << hex << HEAPTRACK_VERSION << '.' << endl;
                return false;
            }
        } else if (reader.mode() == 'I') { // system information
            reader >> systemInfo.pageSize;
            reader >> systemInfo.pages;
        } else {
            cerr << "failed to parse line: " << reader.line() << endl;
        }
    }

    if (!reparsing) {
        totalTime = timeStamp + 1;
    }

    handleTimeStamp(timeStamp, totalTime);

    return true;
}

Allocation& AccumulatedTraceData::findAllocation(const TraceIndex traceIndex)
{
    if (traceIndex < m_maxAllocationTraceIndex) {
        // only need to search when the trace index is previously known
        auto it = lower_bound(allocations.begin(), allocations.end(), traceIndex,
                            [] (const Allocation& allocation, const TraceIndex traceIndex) -> bool {
                                return allocation.traceIndex < traceIndex;
                            });
        assert(it != allocations.end());
        assert(it->traceIndex == traceIndex);
        return *it;
    } else if (traceIndex == m_maxAllocationTraceIndex && !allocations.empty()) {
        // reuse the last allocation
        assert(allocations.back().traceIndex == traceIndex);
    } else {
        // actually a new allocation
        Allocation allocation;
        allocation.traceIndex = traceIndex;
        allocations.push_back(allocation);
        m_maxAllocationTraceIndex = traceIndex;
    }
    return allocations.back();
}

InstructionPointer AccumulatedTraceData::findIp(const IpIndex ipIndex) const
{
    if (!ipIndex || ipIndex.index > instructionPointers.size()) {
        return {};
    } else {
        return instructionPointers[ipIndex.index - 1];
    }
}

TraceNode AccumulatedTraceData::findTrace(const TraceIndex traceIndex) const
{
    if (!traceIndex || traceIndex.index > traces.size()) {
        return {};
    } else {
        return traces[traceIndex.index - 1];
    }
}

bool AccumulatedTraceData::isStopIndex(const StringIndex index) const
{
    return find(stopIndices.begin(), stopIndices.end(), index) != stopIndices.end();
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s

class C {
    struct S; // expected-note {{previously declared 'private' here}}
public:

    struct S {}; // expected-error {{'S' redeclared with 'public' access}}
};

struct S {
    class C; // expected-note {{previously declared 'public' here}}

private:
    class C { }; // expected-error {{'C' redeclared with 'private' access}}
};

class T {
protected:
    template<typename T> struct A; // expected-note {{previously declared 'protected' here}}

private:
    template<typename T> struct A {}; // expected-error {{'A' redeclared with 'private' access}}
};

// PR5573
namespace test1 {
  class A {
  private:
    class X; // expected-note {{previously declared 'private' here}} \
             // expected-note {{previous declaration is here}}
  public:
    class X; // expected-error {{'X' redeclared with 'public' access}} \
             // expected-warning {{class member cannot be redeclared}}
    class X {};
  };
}

// PR15209
namespace PR15209 {
  namespace alias_templates {
    template<typename T1, typename T2> struct U { };
    template<typename T1> using W = U<T1, float>;

    class A {
      typedef int I;
      static constexpr I x = 0; // expected-note {{implicitly declared private here}}
      static constexpr I y = 42; // expected-note {{implicitly declared private here}}
      friend W<int>;
    };

    template<typename T1>
    struct U<T1, float>  {
      int v_;
      // the following will trigger for U<float, float> instantiation, via W<float>
      U() : v_(A::x) { } // expected-error {{'x' is a private member of 'PR15209::alias_templates::A'}}
    };

    template<typename T1>
    struct U<T1, int> {
      int v_;
      U() : v_(A::y) { } // expected-error {{'y' is a private member of 'PR15209::alias_templates::A'}}
    };

    template struct U<int, int>; // expected-note {{in instantiation of member function 'PR15209::alias_templates::U<int, int>::U' requested here}}

    void f()
    {
      W<int>();
      // we should issue diagnostics for the following
      W<float>(); // expected-note {{in instantiation of member function 'PR15209::alias_templates::U<float, float>::U' requested here}}
    }
  }

  namespace templates {
    class A {
      typedef int I;  // expected-note {{implicitly declared private here}}
      static constexpr I x = 0; // expected-note {{implicitly declared private here}}

      template<int> friend struct B;
      template<int> struct C;
      template<template<int> class T> friend struct TT;
      template<typename T> friend void funct(T);
    };
    template<A::I> struct B { };

    template<A::I> struct A::C { };

    template<template<A::I> class T> struct TT {
      T<A::x> t;
    };

    template struct TT<B>;
    template<A::I> struct D { };  // expected-error {{'I' is a private member of 'PR15209::templates::A'}}
    template struct TT<D>;

    // function template case
    template<typename T>
    void funct(T)
    {
      (void)A::x;
    }

    template void funct<int>(int);

    void f()
    {
      (void)A::x;  // expected-error {{'x' is a private member of 'PR15209::templates::A'}}
    }
  }
}
<commit_msg>Add a testcase for PR7434, which is a bug we no longer appear to have.<commit_after>// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s

class C {
    struct S; // expected-note {{previously declared 'private' here}}
public:

    struct S {}; // expected-error {{'S' redeclared with 'public' access}}
};

struct S {
    class C; // expected-note {{previously declared 'public' here}}

private:
    class C { }; // expected-error {{'C' redeclared with 'private' access}}
};

class T {
protected:
    template<typename T> struct A; // expected-note {{previously declared 'protected' here}}

private:
    template<typename T> struct A {}; // expected-error {{'A' redeclared with 'private' access}}
};

// PR5573
namespace test1 {
  class A {
  private:
    class X; // expected-note {{previously declared 'private' here}} \
             // expected-note {{previous declaration is here}}
  public:
    class X; // expected-error {{'X' redeclared with 'public' access}} \
             // expected-warning {{class member cannot be redeclared}}
    class X {};
  };
}

// PR15209
namespace PR15209 {
  namespace alias_templates {
    template<typename T1, typename T2> struct U { };
    template<typename T1> using W = U<T1, float>;

    class A {
      typedef int I;
      static constexpr I x = 0; // expected-note {{implicitly declared private here}}
      static constexpr I y = 42; // expected-note {{implicitly declared private here}}
      friend W<int>;
    };

    template<typename T1>
    struct U<T1, float>  {
      int v_;
      // the following will trigger for U<float, float> instantiation, via W<float>
      U() : v_(A::x) { } // expected-error {{'x' is a private member of 'PR15209::alias_templates::A'}}
    };

    template<typename T1>
    struct U<T1, int> {
      int v_;
      U() : v_(A::y) { } // expected-error {{'y' is a private member of 'PR15209::alias_templates::A'}}
    };

    template struct U<int, int>; // expected-note {{in instantiation of member function 'PR15209::alias_templates::U<int, int>::U' requested here}}

    void f()
    {
      W<int>();
      // we should issue diagnostics for the following
      W<float>(); // expected-note {{in instantiation of member function 'PR15209::alias_templates::U<float, float>::U' requested here}}
    }
  }

  namespace templates {
    class A {
      typedef int I;  // expected-note {{implicitly declared private here}}
      static constexpr I x = 0; // expected-note {{implicitly declared private here}}

      template<int> friend struct B;
      template<int> struct C;
      template<template<int> class T> friend struct TT;
      template<typename T> friend void funct(T);
    };
    template<A::I> struct B { };

    template<A::I> struct A::C { };

    template<template<A::I> class T> struct TT {
      T<A::x> t;
    };

    template struct TT<B>;
    template<A::I> struct D { };  // expected-error {{'I' is a private member of 'PR15209::templates::A'}}
    template struct TT<D>;

    // function template case
    template<typename T>
    void funct(T)
    {
      (void)A::x;
    }

    template void funct<int>(int);

    void f()
    {
      (void)A::x;  // expected-error {{'x' is a private member of 'PR15209::templates::A'}}
    }
  }
}

namespace PR7434 {
  namespace comment0 {
    template <typename T> struct X;
    namespace N {
    class Y {
      template<typename T> friend struct X;
      int t; // expected-note {{here}}
    };
    }
    template<typename T> struct X {
      X() { (void)N::Y().t; } // expected-error {{private}}
    };
    X<char> x;
  }
  namespace comment2 {
    struct X;
    namespace N {
    class Y {
      friend struct X;
      int t; // expected-note {{here}}
    };
    }
    struct X {
      X() { (void)N::Y().t; } // expected-error {{private}}
    };
  }
}
<|endoftext|>


<commit_before>#include "serializer.h"
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>

namespace rapscallion {

void serializer<std::uint_least64_t>::write(Serializer& s, std::uint_least64_t value) {
  while (value >= 0x80) {
    s.addByte((uint8_t)(value & 0x7F) | 0x80);
    value >>= 7;
  }
  s.addByte((uint8_t)value);
}
void serializer<long>::write(Serializer& s, const long v) {
  std::uint_least64_t val = (std::abs(v) << 1) | (v < 0 ? 1 : 0);
  serializer<std::uint_least64_t>::write(s, val);
}
void serializer<int>::write(Serializer& s, const int v) {
  serializer<long>::write(s, v);
}
void serializer<std::string>::write(Serializer& s, const std::string& value) {
  serializer<std::uint_least64_t>::write(s, value.size());
  for (auto& c : value) s.addByte(c);
}
void serializer<bool>::write(Serializer& s, const bool b) {
  serializer<std::uint_least64_t>::write(s, b ? 1 : 0);
}

namespace {
  enum Type {
    Zero,
    Infinity,
    NaN,
    Normal
  };
  struct float_repr {
    // Can fit an exponent of 32-2=20 bits, can support octuple-precision IEEE754 floats
    std::int_least32_t exponent;
    // Can support double precision IEEE754 floats (quadruple requires 112 bits, octuple 236 bits)
    std::uint_least64_t fraction;
    // One bit reserved for sign bit
    static constexpr unsigned fraction_bits = 63 - 1;
    bool is_negative;
    Type type;
  };
  auto bitreverse(std::uint_least64_t b) -> decltype(b)
  {
    b = ((b & 0xFFFFFFFF00000000ULL) >> 32) | ((b & 0x00000000FFFFFFFFULL) << 32);
    b = ((b & 0xFFFF0000FFFF0000ULL) >> 16) | ((b & 0x0000FFFF0000FFFFULL) << 16);
    b = ((b & 0xFF00FF00FF00FF00ULL) >>  8) | ((b & 0x00FF00FF00FF00FFULL) <<  8);
    b = ((b & 0xF0F0F0F0F0F0F0F0ULL) >>  4) | ((b & 0x0F0F0F0F0F0F0F0FULL) << 4);
    b = ((b & 0xCCCCCCCCCCCCCCCCULL) >>  2) | ((b & 0x3333333333333333ULL) <<  2);
    b = ((b & 0xAAAAAAAAAAAAAAAAULL) >>  1) | ((b & 0x5555555555555555ULL) <<  1);
    return b;
  }
}

template <>
struct serializer<float_repr> {
  static void write(Serializer& s, float_repr const &b) {
    // Using multiplication to avoid bit shifting a signed integer
    switch(b.type) {
      default:
        {
          serializer<decltype(+b.exponent)>::write(s, b.is_negative ? -b.type : b.type);
        }
        break;
      case Normal:
        {
          const decltype(b.exponent) exponent
            = b.exponent * 2 + (b.exponent < 0 ? -b.is_negative : b.is_negative);
          const decltype(b.fraction) reversed_fraction
            = bitreverse(b.fraction);
          serializer<decltype(+exponent)>::write(s, exponent < 0 ? exponent - 2 : exponent + 3);
          serializer<decltype(+b.fraction)>::write(s, reversed_fraction);
        }
        break;
    };
  }
  static float_repr read(Deserializer& s) {
    float_repr result;
    auto exponent = serializer<decltype(result.exponent)>::read(s);
    if (exponent < 3 && exponent >= -2) {
      result.is_negative   = (exponent < 0);
      result.type          = (Type)std::abs(exponent);
    } else {
      exponent = (exponent < 0) ? exponent + 2 : exponent - 3;
      result.is_negative   = !!((exponent/ 1) % 2);
      result.type = Normal;
      result.exponent      = exponent / 2;
      const auto reversed_fraction = serializer<decltype(result.fraction)>::read(s);
      result.fraction      = bitreverse(reversed_fraction);
    }
    return result;
  }
};

void serializer<double>::write(Serializer& s, double const b) {
  switch (std::fpclassify(b)) {
    case FP_ZERO:
      serializer<float_repr>::write(s, { 0, 0, !!std::signbit(b), Zero });
      break;
    case FP_INFINITE:
      serializer<float_repr>::write(s, { 0, 0, !!std::signbit(b), Infinity });
      break;
    case FP_NAN:
      // The bit reversal is to ensure the most efficient encoding can be used
      serializer<float_repr>::write(s, { 0, 0, false, NaN });
      break;
    case FP_NORMAL:
    case FP_SUBNORMAL:
      float_repr repr;
      repr.type = Normal;
      repr.is_negative = !!std::signbit(b);
      // Make the fraction a positive integer
      repr.fraction = std::ldexp(std::abs(std::frexp(b, &repr.exponent)), repr.fraction_bits);
      serializer<decltype(repr)>::write(s, repr);
      break;
  }
}

double serializer<double>::read(Deserializer& s) {
  const auto repr = serializer<float_repr>::read(s);
  switch(repr.type) {
    case Zero:
      return (repr.is_negative ? -0.0 : 0.0);
    case Infinity:
      return repr.is_negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
    case NaN:
      return std::numeric_limits<double>::quiet_NaN();
    default:
      return (repr.is_negative ? -1.0 : 1.0) * std::ldexp(static_cast<double>(repr.fraction), repr.exponent - repr.fraction_bits);
  }
}

void serializer<float>::write(Serializer& s, float const b) {
  serializer<double>::write(s, b);
}
float serializer<float>::read(Deserializer& s) {
  return serializer<double>::read(s);
}

std::uint_least64_t serializer<std::uint_least64_t>::read(Deserializer& s) {
  std::uint_least64_t val = 0,
    offs = 0,
    b = s.getByte();
  while (b & 0x80) {
    val |= (b & 0x7F) << offs;
    offs += 7;
    b = s.getByte();
  }
  val |= b << offs;
  return val;
}
long serializer<long>::read(Deserializer& s) {
  const auto val = serializer<std::uint_least64_t>::read(s);
  auto value = static_cast<long>(val >> 1);
  if (val & 1) value = -value;
  return value;
}
int serializer<int>::read(Deserializer& s) {
  return serializer<long>::read(s);
}
std::string serializer<std::string>::read(Deserializer& s) {
  const auto length = serializer<std::uint_least64_t>::read(s);
  const uint8_t* ptr = s.ptr;
  const uint8_t* end = ptr + length;
  if (end > s.end)
    throw parse_exception("buffer underrun");
  s.ptr = end;
  return std::string(reinterpret_cast<const char*>(ptr), length);
}
bool serializer<bool>::read(Deserializer& s) {
  return serializer<std::uint_least64_t>::read(s) > 0;
}

}
<commit_msg>Make sure we can retain the sign of -0.0<commit_after>#include "serializer.h"
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>

namespace rapscallion {

void serializer<std::uint_least64_t>::write(Serializer& s, std::uint_least64_t value) {
  while (value >= 0x80) {
    s.addByte((uint8_t)(value & 0x7F) | 0x80);
    value >>= 7;
  }
  s.addByte((uint8_t)value);
}
void serializer<long>::write(Serializer& s, const long v) {
  std::uint_least64_t val = (std::abs(v) << 1) | (v < 0 ? 1 : 0);
  serializer<std::uint_least64_t>::write(s, val);
}
void serializer<int>::write(Serializer& s, const int v) {
  serializer<long>::write(s, v);
}
void serializer<std::string>::write(Serializer& s, const std::string& value) {
  serializer<std::uint_least64_t>::write(s, value.size());
  for (auto& c : value) s.addByte(c);
}
void serializer<bool>::write(Serializer& s, const bool b) {
  serializer<std::uint_least64_t>::write(s, b ? 1 : 0);
}

namespace {
  enum Type {
    // First position of enum, because it is zero, must be covered with a value for which the sign doesn't matter
    NaN,
    Infinity,
    Zero,
    Normal
  };
  struct float_repr {
    // Can fit an exponent of 32-2=20 bits, can support octuple-precision IEEE754 floats
    std::int_least32_t exponent;
    // Can support double precision IEEE754 floats (quadruple requires 112 bits, octuple 236 bits)
    std::uint_least64_t fraction;
    // One bit reserved for sign bit
    static constexpr unsigned fraction_bits = 63 - 1;
    bool is_negative;
    Type type;
  };
  auto bitreverse(std::uint_least64_t b) -> decltype(b)
  {
    b = ((b & 0xFFFFFFFF00000000ULL) >> 32) | ((b & 0x00000000FFFFFFFFULL) << 32);
    b = ((b & 0xFFFF0000FFFF0000ULL) >> 16) | ((b & 0x0000FFFF0000FFFFULL) << 16);
    b = ((b & 0xFF00FF00FF00FF00ULL) >>  8) | ((b & 0x00FF00FF00FF00FFULL) <<  8);
    b = ((b & 0xF0F0F0F0F0F0F0F0ULL) >>  4) | ((b & 0x0F0F0F0F0F0F0F0FULL) << 4);
    b = ((b & 0xCCCCCCCCCCCCCCCCULL) >>  2) | ((b & 0x3333333333333333ULL) <<  2);
    b = ((b & 0xAAAAAAAAAAAAAAAAULL) >>  1) | ((b & 0x5555555555555555ULL) <<  1);
    return b;
  }
}

template <>
struct serializer<float_repr> {
  static void write(Serializer& s, float_repr const &b) {
    // Using multiplication to avoid bit shifting a signed integer
    switch(b.type) {
      default:
        {
          serializer<decltype(+b.exponent)>::write(s, b.is_negative ? -b.type : b.type);
        }
        break;
      case Normal:
        {
          const decltype(b.exponent) exponent
            = b.exponent * 2 + (b.exponent < 0 ? -b.is_negative : b.is_negative);
          const decltype(b.fraction) reversed_fraction
            = bitreverse(b.fraction);
          serializer<decltype(+exponent)>::write(s, exponent < 0 ? exponent - 2 : exponent + 3);
          serializer<decltype(+b.fraction)>::write(s, reversed_fraction);
        }
        break;
    };
  }
  static float_repr read(Deserializer& s) {
    float_repr result;
    auto exponent = serializer<decltype(result.exponent)>::read(s);
    if (exponent < 3 && exponent >= -2) {
      result.is_negative   = (exponent < 0);
      result.type          = (Type)std::abs(exponent);
    } else {
      exponent = (exponent < 0) ? exponent + 2 : exponent - 3;
      result.is_negative   = !!((exponent/ 1) % 2);
      result.type = Normal;
      result.exponent      = exponent / 2;
      const auto reversed_fraction = serializer<decltype(result.fraction)>::read(s);
      result.fraction      = bitreverse(reversed_fraction);
    }
    return result;
  }
};

void serializer<double>::write(Serializer& s, double const b) {
  switch (std::fpclassify(b)) {
    case FP_ZERO:
      serializer<float_repr>::write(s, { 0, 0, !!std::signbit(b), Zero });
      break;
    case FP_INFINITE:
      serializer<float_repr>::write(s, { 0, 0, !!std::signbit(b), Infinity });
      break;
    case FP_NAN:
      // The bit reversal is to ensure the most efficient encoding can be used
      serializer<float_repr>::write(s, { 0, 0, false, NaN });
      break;
    case FP_NORMAL:
    case FP_SUBNORMAL:
      float_repr repr;
      repr.type = Normal;
      repr.is_negative = !!std::signbit(b);
      // Make the fraction a positive integer
      repr.fraction = std::ldexp(std::abs(std::frexp(b, &repr.exponent)), repr.fraction_bits);
      serializer<decltype(repr)>::write(s, repr);
      break;
  }
}

double serializer<double>::read(Deserializer& s) {
  const auto repr = serializer<float_repr>::read(s);
  switch(repr.type) {
    case Zero:
      return (repr.is_negative ? -0.0 : 0.0);
    case Infinity:
      return repr.is_negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
    case NaN:
      return std::numeric_limits<double>::quiet_NaN();
    default:
      return (repr.is_negative ? -1.0 : 1.0) * std::ldexp(static_cast<double>(repr.fraction), repr.exponent - repr.fraction_bits);
  }
}

void serializer<float>::write(Serializer& s, float const b) {
  serializer<double>::write(s, b);
}
float serializer<float>::read(Deserializer& s) {
  return serializer<double>::read(s);
}

std::uint_least64_t serializer<std::uint_least64_t>::read(Deserializer& s) {
  std::uint_least64_t val = 0,
    offs = 0,
    b = s.getByte();
  while (b & 0x80) {
    val |= (b & 0x7F) << offs;
    offs += 7;
    b = s.getByte();
  }
  val |= b << offs;
  return val;
}
long serializer<long>::read(Deserializer& s) {
  const auto val = serializer<std::uint_least64_t>::read(s);
  auto value = static_cast<long>(val >> 1);
  if (val & 1) value = -value;
  return value;
}
int serializer<int>::read(Deserializer& s) {
  return serializer<long>::read(s);
}
std::string serializer<std::string>::read(Deserializer& s) {
  const auto length = serializer<std::uint_least64_t>::read(s);
  const uint8_t* ptr = s.ptr;
  const uint8_t* end = ptr + length;
  if (end > s.end)
    throw parse_exception("buffer underrun");
  s.ptr = end;
  return std::string(reinterpret_cast<const char*>(ptr), length);
}
bool serializer<bool>::read(Deserializer& s) {
  return serializer<std::uint_least64_t>::read(s) > 0;
}

}
<|endoftext|>


<commit_before>/**
 * @file  shared_ptr.hpp
 * @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 *  This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
 * or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
 * and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
 *  If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

namespace Log
{

//
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
//    get a kind of universal easy to use "shared_ptr" type
//
#ifdef LOGGER_USE_BOOST_SHARED_PTR
    // Use Boost only if explicitly told
    #include <boost/shared_ptr.hpp>
    using boost::shared_ptr;
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
#elif (defined(__GNUC__) && (__GNUC__ > 4 || \
      (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
    #include <memory>
    using std::shared_ptr
#elif (defined(__GNUC__) && (__GNUC__ == 4) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.0/4.1/4.2 have std::shared_ptr support when when called with -std=c++0x
    #include <tr1/memory>
    using std::tr1:shared_ptr;
#elif defined(__clang__)
    // Clang 2.9 and above ? What is the most appropriate feature to check for shared_ptr support in Clang ?
    __has_feature(cxx_nullptr)
    #include <memory>
    using std::shared_ptr;
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    // Visual Studio 2010 compile by default in C++11 mode
    #include <memory>
    using std::shared_ptr;
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
    // Visual Studio 2008 : beware, TR1 is provided with the Service Pack 1 only !
    #include <memory>
    using std::tr1:shared_ptr;
#else

/**
 * @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 * shared_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * and sharing this ownership with a reference counter.
 * It destroys the object when the last shared pointer pointing to it is destroyed or reset.
 */
template<class T>
class shared_ptr
{
public:
    /// @brief Default constructor
    shared_ptr(void) throw() : // nothrow
        px(NULL),
        pn(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit shared_ptr(T* p) : // throw std::bad_alloc
        px(p),
        pn(NULL)
    {
        acquire();
    }
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    shared_ptr(const shared_ptr& ptr) : // throw std::bad_alloc
        px(ptr.px),
        pn(ptr.pn)
    {
        acquire();
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    shared_ptr& operator=(shared_ptr ptr) throw() // nothrow
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor release its ownership
    inline ~shared_ptr(void) throw() // nothrow
    {
        release();
    }
    /// @brief this reset release its ownership
    inline void reset(void) throw() // nothrow
    {
        release();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // nothrow
    {
        release();
        px = p;
        acquire();
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(shared_ptr& lhs) throw() // nothrow
    {
        std::swap(px, lhs.px);
        std::swap(pn, lhs.pn);
    }

    // reference counter operations :
    inline operator bool() const throw() // nothrow
    {
        return (0 < use_count());
    }
    inline bool unique(void)  const throw() // nothrow
    {
        return (1 == use_count());
    }
    long use_count(void)  const throw() // nothrow
    {
        long count = 0;
        if (NULL != pn)
        {
            count = *pn;
        }
        return count;
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // nothrow
    {
        return *px;
    }
    inline T* operator->() const throw() // nothrow
    {
        return px;
    }
    inline T* get(void)  const throw() // nothrow
    {
        return px;
    }

    // comparaison operators
    inline bool operator== (const shared_ptr& ptr) const
    {
        return (px == ptr.px);
    }
    inline bool operator== (const T* p) const
    {
        return (px == p);
    }
    inline bool operator!= (const shared_ptr& ptr) const
    {
        return (px != ptr.px);
    }
    inline bool operator!= (const T* p) const
    {
        return (px != p);
    }
    inline bool operator<= (const shared_ptr& ptr) const
    {
        return (px <= ptr.px);
    }
    inline bool operator<= (const T* p) const
    {
        return (px <= p);
    }
    inline bool operator< (const shared_ptr& ptr) const
    {
        return (px < ptr.px);
    }
    inline bool operator< (const T* p) const
    {
        return (px < p);
    }
    inline bool operator>= (const shared_ptr& ptr) const
    {
        return (px >= ptr.px);
    }
    inline bool operator>= (const T* p) const
    {
        return (px >= p);
    }
    inline bool operator> (const shared_ptr& ptr) const
    {
        return (px > ptr.px);
    }
    inline bool operator> (const T* p) const
    {
        return (px > p);
    }

private:
    /// @brief acquire/share the ownership of the px pointer, initializing the reference counter
    void acquire(void)
    {
        if (NULL != px)
        {
            if (NULL == pn)
            {
                try
                {
                    pn = new long(1);
                }
                catch (std::bad_alloc&)
                {
                    delete px;
                    throw;
                }
            }
            else
            {
                ++(*pn);
            }
        }
    }

    /// @brief release the ownership of the px pointer, destroying the object when appropriate
    void release(void) throw() // nothrow
    {
        if (NULL != pn)
        {
            --(*pn);
            if (0 == *pn)
            {
                delete px;
                px = NULL;
                delete pn;
                pn = NULL;
            }
        }
    }

private:
    T*      px; //!< Native pointer
    long*   pn; //!< Reference counter
};

#endif // LOGGER_USE_BOOST_SHARED_PTR

} // namespace Log
<commit_msg>Updated minimal shared_ptr.hpp with recent fixes and cleanup<commit_after>/**
 * @file  shared_ptr.hpp
 * @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 *  This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
 * or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
 * and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
 *  If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

namespace Log
{

//
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
//    get a kind of universal easy to use "shared_ptr" type
//
#ifdef LOGGER_USE_BOOST_SHARED_PTR
    // Use Boost only if explicitly told
    #include <boost/shared_ptr.hpp>
    using boost::shared_ptr;
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
#elif (defined(__GNUC__) && (__GNUC__ > 4 || \
      (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
    #include <memory>
    using std::shared_ptr
#elif (defined(__GNUC__) && (__GNUC__ == 4) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.0/4.1/4.2 have std::shared_ptr support when when called with -std=c++0x
    #include <tr1/memory>
    using std::tr1:shared_ptr;
#elif defined(__clang__)
    // Clang 2.9 and above ? What is the most appropriate feature to check for shared_ptr support in Clang ?
    __has_feature(cxx_nullptr)
    #include <memory>
    using std::shared_ptr;
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    // Visual Studio 2010 compile by default in C++11 mode
    #include <memory>
    using std::shared_ptr;
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
    // Visual Studio 2008 : beware, TR1 is provided with the Service Pack 1 only !
    #include <memory>
    using std::tr1:shared_ptr;
#else

#include <cstddef>      // NULL
#include <algorithm>    // std::swap

// can be replaced by other error mechanism
#include <cassert>
#define SHARED_ASSERT(x)    assert(x)

/**
 * @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 * shared_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * and sharing this ownership with a reference counter.
 * It destroys the object when the last shared pointer pointing to it is destroyed or reset.
 */
template<class T>
class shared_ptr
{
public:
   typedef T element_type;

   /// @brief Default constructor
    shared_ptr(void) throw() : // never throws
        px(NULL),
        pn(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit shared_ptr(T* p) : // may throw std::bad_alloc
      //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
        pn(NULL)
    {
        acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Constructor to share ownership. Warning : to be used for pointer_cast only ! (does not manage two separate <T> and <U> pointers)
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr, T* p) :
     //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
       pn(ptr.pn)
    {
       acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Copy constructor to convert from another pointer type
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr) throw() : // never throws (see comment below)
      //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(static_cast<typename shared_ptr<T>::element_type*>(ptr.px));   // will never throw std::bad_alloc
    }
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below)
       //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(ptr.px);   // will never throw std::bad_alloc
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    shared_ptr& operator=(shared_ptr ptr) throw() // never throws
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor releases its ownership
    inline ~shared_ptr(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset releases its ownership
    inline void reset(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // may throw std::bad_alloc
    {
        SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
        release();
        acquire(p); // may throw std::bad_alloc
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(shared_ptr& lhs) throw() // never throws
    {
        // Would be nice to enable use of ustl::swap by define
        std::swap(px, lhs.px);
        std::swap(pn, lhs.pn);
    }

    // reference counter operations :
    inline operator bool() const throw() // never throws
    {
        return (0 < use_count());
    }
    inline bool unique(void)  const throw() // never throws
    {
        return (1 == use_count());
    }
    long use_count(void)  const throw() // never throws
    {
        long count = 0;
        if (NULL != pn)
        {
            count = *pn;
        }
        return count;
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return *px;
    }
    inline T* operator->() const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return px;
    }
    inline T* get(void)  const throw() // never throws
    {
        // no assert, car return NULL
        return px;
    }

private:
    /// @brief acquire/share the ownership of the px pointer, initializing the reference counter
    void acquire(T* p) // may throw std::bad_alloc
    {
        if (NULL != p)
        {
            if (NULL == pn)
            {
                try
                {
                    pn = new long(1); // may throw std::bad_alloc
                }
                catch (std::bad_alloc&)
                {
                    delete p;
                    throw; // rethrow the std::bad_alloc
                }
            }
            else
            {
                ++(*pn);
            }
        }
        // here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more
        px = p;
    }

    /// @brief release the ownership of the px pointer, destroying the object when appropriate
    void release(void) throw() // never throws
    {
        if (NULL != pn)
        {
            --(*pn);
            if (0 == *pn)
            {
                delete px;
                delete pn;
            }
            px = NULL;
            pn = NULL;
        }
    }

private:
    // This allow pointer_cast functions to share the reference counter between different shared_ptr types
    template<class U>
    friend class shared_ptr;

private:
    T*      px; //!< Native pointer
    long*   pn; //!< Reference counter
};

// comparaison operators
template<class T, class U> inline bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() > r.get());
}

// static cast of shared_ptr
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    return shared_ptr<T>(ptr, static_cast<typename shared_ptr<T>::element_type*>(ptr.get()));
}

// dynamic cast of shared_ptr
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    T* p = dynamic_cast<typename shared_ptr<T>::element_type*>(ptr.get());
    if (NULL != p)
    {
        return shared_ptr<T>(ptr, p);
    }
    else
    {
        return shared_ptr<T>();
    }
}

} // namespace Log
<|endoftext|>


<commit_before>// Copyright 2017 The Johns Hopkins University Applied Physics Laboratory.
// Licensed under the MIT License. See LICENSE.txt in the project root for full license information.

#include <cstdio>
#include <ctime>
#include "orthoimage.h"
#include "shr3d.h"

// Print command line arguments.
void printArguments() {
    printf("Command line arguments: <Input File (LAS|TIF)> <Options>\n");
    printf("Options:\n");
    printf("  DH=    horizontal uncertainty (meters)\n");
    printf("  DZ=    vertical uncertainty (meters)\n");
    printf("  AGL=   minimum building height above ground level (meters)\n");
    printf("  AREA=	 minimum building area (meters)\n");
    printf("  EGM96  set this flag to write vertical datum = EGM96\n");
    printf("  FOPEN  set this flag for ground detection under dense foliage\n");
    printf("Examples:\n");
    printf("  For EO DSM:    shr3d dsm.tif DH=5.0 DZ=1.0 AGL=2 AREA=50.0 EGM96\n");
    printf("  For lidar DSM: shr3d dsm.tif DH=1.0 DZ=1.0 AGL=2.0 AREA=50.0\n");
    printf("  For lidar LAS: shr3d pts.las DH=1.0 DZ=1.0 AGL=2.0 AREA=50.0\n");
}

// Main program for bare earth classification.
int main(int argc, char **argv) {
    // If no parameters, then print command line arguments.
    if (argc < 4) {
        printf("Number of arguments = %d\n", argc);
        for (int i = 0; i < argc; i++) {
            printf("ARG[%d] = %s\n", i, argv[i]);
        }
        printArguments();
        return -1;
    }

    // Get command line arguments and confirm they are valid.
    double gsd_meters = 0.0;
    double dh_meters = 0.0;
    double dz_meters = 0.0;
    double agl_meters = 0.0;
    double min_area_meters = 50.0;
    bool egm96 = false;
    bool convert = false;
    char inputFileName[1024];
    sprintf(inputFileName, argv[1]);
    for (int i = 2; i < argc; i++) {
        if (strstr(argv[i], "DH=")) { dh_meters = atof(&(argv[i][3])); }
        if (strstr(argv[i], "DZ=")) { dz_meters = atof(&(argv[i][3])); }
        if (strstr(argv[i], "AGL=")) { agl_meters = atof(&(argv[i][4])); }
        if (strstr(argv[i], "AREA=")) { min_area_meters = atof(&(argv[i][5])); }
        if (strstr(argv[i], "EGM96")) { egm96 = true; }
        if (strstr(argv[i], "CONVERT")) { convert = true; }
    }
    if ((dh_meters == 0.0) || (dz_meters == 0.0) || (agl_meters == 0.0)) {
        printf("DH_METERS = %f\n", dh_meters);
        printf("DZ_METERS = %f\n", dz_meters);
        printf("AGL_METERS = %f\n", agl_meters);
        printf("Error: All three values must be nonzero.\n");
        printArguments();
        return -1;
    }

    // Initialize the timer.
    time_t t0;
    time(&t0);

    // If specified, then convert to GDAL TIFF.
    char readFileName[1024];
    strcpy(readFileName, inputFileName);
    if (convert) {
        char cmd[4096];
        sprintf(readFileName, "temp.tif\0");
        sprintf(cmd, ".\\gdal\\gdal_translate %s temp.tif\n", inputFileName);
        system(cmd);
    }

    // Read DSM as SHORT.
    // Input can be GeoTIFF or LAS.
    shr3d::OrthoImage<unsigned short> dsmImage;
    shr3d::OrthoImage<unsigned short> minImage;
    printf("Reading DSM as SHORT.\n");
    int len = (int) strlen(inputFileName);
    char *ext = &inputFileName[len - 3];
    printf("File Type = .%s\n", ext);
    if (strcmp(ext, "tif") == 0) {
        bool ok = dsmImage.read(readFileName);
        if (!ok) return -1;
    } else if ((strcmp(ext, "las") == 0) || (strcmp(ext, "bpf") == 0)) {
        // First get the max Z values for the DSM.
        bool ok = dsmImage.readFromPointCloud(inputFileName, (float) dh_meters, shr3d::MAX_VALUE);
        if (!ok) return -1;

        // Median filter, replacing only points differing by more than the AGL threshold.
        dsmImage.medianFilter(1, (unsigned int) (agl_meters / dsmImage.scale));

        // Fill small voids in the DSM.
        dsmImage.fillVoidsPyramid(true, 2);

        // Write the DSM image as FLOAT.
        char dsmOutFileName[1024];
        sprintf(dsmOutFileName, "%s_DSM.tif\0", inputFileName);
        dsmImage.write(dsmOutFileName, true);

        // Now get the minimum Z values for the DTM.
        ok = minImage.readFromPointCloud(inputFileName, (float) dh_meters, shr3d::MIN_VALUE);
        if (!ok) return -1;

        // Median filter, replacing only points differing by more than the AGL threshold.
        minImage.medianFilter(1, (unsigned int) (agl_meters / minImage.scale));

        // Fill small voids in the DSM.
        minImage.fillVoidsPyramid(true, 2);

        // Write the MIN image as FLOAT.
        char minOutFileName[1024];
        sprintf(minOutFileName, "%s_MIN.tif\0", inputFileName);
        minImage.write(minOutFileName, true);

        // Find many of the trees by comparing MIN and MAX. Set their values to void.
        for (int j = 0; j < dsmImage.height; j++) {
            for (int i = 0; i < dsmImage.width; i++) {
                float minValue = (float) minImage.data[j][i];

                // This check is to avoid penalizing spurious returns under very tall buildings.
                // CAUTION: This is a hack to address an observed lidar sensor issue and may not generalize well.
                if (((float) dsmImage.data[j][i] - minValue) < (40.0 / minImage.scale)) {
                    // If this is in the trees, then set to void.
                    bool found = false;
                    double threshold = dz_meters / dsmImage.scale;
                    int i1 = MAX(0, i - 1);
                    int i2 = MIN(i + 1, dsmImage.width - 1);
                    int j1 = MAX(0, j - 1);
                    int j2 = MIN(j + 1, dsmImage.height - 1);
                    for (int jj = j1; jj <= j2; jj++) {
                        for (int ii = i1; ii <= i2; ii++) {
                            float diff = (float) dsmImage.data[jj][ii] - minValue;
                            if (diff < threshold) found = true;
                        }
                    }
                    if (!found) dsmImage.data[j][i] = 0;
                }
            }
        }

        // Write the DSM2 image as FLOAT.
        char dsm2OutFileName[1024];
        sprintf(dsm2OutFileName, "%s_DSM2.tif\0", inputFileName);
        dsmImage.write(dsm2OutFileName, true);
    } else {
        printf("Error: Unrecognized file type.");
        return -1;
    }

    // Convert horizontal and vertical uncertainty values to bin units.
    int dh_bins = MAX(1, (int) floor(dh_meters / dsmImage.gsd));
    printf("DZ_METERS = %f\n", dz_meters);
    printf("DH_METERS = %f\n", dh_meters);
    printf("DH_BINS = %d\n", dh_bins);
    unsigned int dz_short = (unsigned int) (dz_meters / dsmImage.scale);
    printf("DZ_SHORT = %d\n", dz_short);
    printf("AGL_METERS = %f\n", agl_meters);
    unsigned int agl_short = (unsigned int) (agl_meters / dsmImage.scale);
    printf("AGL_SHORT = %d\n", agl_short);
    printf("AREA_METERS = %f\n", min_area_meters);

    // Generate label image.
    shr3d::OrthoImage<unsigned long> labelImage;
    labelImage.Allocate(dsmImage.width, dsmImage.height);
    labelImage.easting = dsmImage.easting;
    labelImage.northing = dsmImage.northing;
    labelImage.zone = dsmImage.zone;
    labelImage.gsd = dsmImage.gsd;

    // Allocate a DTM image as SHORT and copy in the DSM values.
    shr3d::OrthoImage<unsigned short> dtmImage;
    dtmImage.Allocate(dsmImage.width, dsmImage.height);
    dtmImage.easting = dsmImage.easting;
    dtmImage.northing = dsmImage.northing;
    dtmImage.zone = dsmImage.zone;
    dtmImage.gsd = dsmImage.gsd;
    dtmImage.scale = dsmImage.scale;
    dtmImage.offset = dsmImage.offset;
    dtmImage.bands = dsmImage.bands;
    for (int j = 0; j < dsmImage.height; j++) {
        for (int i = 0; i < dsmImage.width; i++) {
            dtmImage.data[j][i] = minImage.data[j][i];
        }
    }

    // Classify ground points.
    shr3d::Shr3dder::classifyGround(labelImage, dsmImage, dtmImage, dh_bins, dz_short);

    // For DSM voids, also set DTM value to void.
    printf("Setting DTM values to VOID where DSM is VOID...\n");
    for (int j = 0; j < dsmImage.height; j++) {
        for (int i = 0; i < dsmImage.width; i++) {
            if (dsmImage.data[j][i] == 0) dtmImage.data[j][i] = 0;
        }
    }

    // Median filter, replacing only points differing by more than the DZ threshold.
    dtmImage.medianFilter(1, (unsigned int) (dz_meters / dsmImage.scale));

    // Refine the object label image and export building outlines.
    shr3d::Shr3dder::classifyNonGround(dsmImage, dtmImage, labelImage, dz_short, agl_short, (float) min_area_meters);

    // Fill small voids in the DTM after all processing is complete.
    dtmImage.fillVoidsPyramid(true, 2);

    // Write the DTM image as FLOAT.
    char dtmOutFileName[1024];
    sprintf(dtmOutFileName, "%s_DTM.tif\0", inputFileName);
    dtmImage.write(dtmOutFileName, true, egm96);

    // Produce a classification raster image with LAS standard point classes.
    shr3d::OrthoImage<unsigned char> classImage;
    classImage.Allocate(labelImage.width, labelImage.height);
    classImage.easting = dsmImage.easting;
    classImage.northing = dsmImage.northing;
    classImage.zone = dsmImage.zone;
    classImage.gsd = dsmImage.gsd;
    for (int j = 0; j < classImage.height; j++) {
        for (int i = 0; i < classImage.width; i++) {
            // Set default as unlabeled.
            classImage.data[j][i] = LAS_UNCLASSIFIED;

            // Label trees.
            if ((dsmImage.data[j][i] == 0) ||
                (fabs((float) dsmImage.data[j][i] - (float) dtmImage.data[j][i]) > agl_short))
                classImage.data[j][i] = LAS_TREE;

            // Label buildings.
            if (labelImage.data[j][i] == 1) classImage.data[j][i] = LAS_BUILDING;

            // Label ground.
            if (fabs((float) dsmImage.data[j][i] - (float) dtmImage.data[j][i]) < dz_short)
                classImage.data[j][i] = LAS_GROUND;
        }
    }

    // Fill missing labels inside building regions.
    shr3d::Shr3dder::fillInsideBuildings(classImage);

    // Write the classification image.
    char classOutFileName[1024];
    sprintf(classOutFileName, "%s_class.tif\0", inputFileName);
    classImage.write(classOutFileName, false, egm96);
    for (int j = 0; j < classImage.height; j++) {
        for (int i = 0; i < classImage.width; i++) {
            if (classImage.data[j][i] != LAS_BUILDING) classImage.data[j][i] = 0;
        }
    }
    sprintf(classOutFileName, "%s_buildings.tif\0", inputFileName);
    classImage.write(classOutFileName, false, egm96);

    // Report total elapsed time.
    time_t t1;
    time(&t1);
    printf("Total time elapsed = %f seconds\n", double(t1 - t0));
}

<commit_msg>Fixes #2<commit_after>// Copyright 2017 The Johns Hopkins University Applied Physics Laboratory.
// Licensed under the MIT License. See LICENSE.txt in the project root for full license information.

#include <cstdio>
#include <ctime>
#include "orthoimage.h"
#include "shr3d.h"

// Print command line arguments.
void printArguments() {
    printf("Command line arguments: <Input File (LAS|TIF)> <Options>\n");
    printf("Required Options:\n");
    printf("  DH=    horizontal uncertainty (meters)\n");
    printf("  DZ=    vertical uncertainty (meters)\n");
    printf("  AGL=   minimum building height above ground level (meters)\n");
    printf("Options:\n");
    printf("  AREA=	 minimum building area (meters)\n");
    printf("  EGM96  set this flag to write vertical datum = EGM96\n");
    printf("  FOPEN  set this flag for ground detection under dense foliage\n");
    printf("Examples:\n");
    printf("  For EO DSM:    shr3d dsm.tif DH=5.0 DZ=1.0 AGL=2 AREA=50.0 EGM96\n");
    printf("  For lidar DSM: shr3d dsm.tif DH=1.0 DZ=1.0 AGL=2.0 AREA=50.0\n");
    printf("  For lidar LAS: shr3d pts.las DH=1.0 DZ=1.0 AGL=2.0 AREA=50.0\n");
}

// Main program for bare earth classification.
int main(int argc, char **argv) {
    // If no parameters, then print command line arguments.
    if (argc < 4) {
        printf("Number of arguments = %d\n", argc);
        for (int i = 0; i < argc; i++) {
            printf("ARG[%d] = %s\n", i, argv[i]);
        }
        printArguments();
        return -1;
    }

    // Get command line arguments and confirm they are valid.
    double gsd_meters = 0.0;
    double dh_meters = 0.0;
    double dz_meters = 0.0;
    double agl_meters = 0.0;
    double min_area_meters = 50.0;
    bool egm96 = false;
    bool convert = false;
    char inputFileName[1024];
    sprintf(inputFileName, argv[1]);
    for (int i = 2; i < argc; i++) {
        if (strstr(argv[i], "DH=")) { dh_meters = atof(&(argv[i][3])); }
        if (strstr(argv[i], "DZ=")) { dz_meters = atof(&(argv[i][3])); }
        if (strstr(argv[i], "AGL=")) { agl_meters = atof(&(argv[i][4])); }
        if (strstr(argv[i], "AREA=")) { min_area_meters = atof(&(argv[i][5])); }
        if (strstr(argv[i], "EGM96")) { egm96 = true; }
        if (strstr(argv[i], "CONVERT")) { convert = true; }
    }
    if ((dh_meters == 0.0) || (dz_meters == 0.0) || (agl_meters == 0.0)) {
        printf("DH_METERS = %f\n", dh_meters);
        printf("DZ_METERS = %f\n", dz_meters);
        printf("AGL_METERS = %f\n", agl_meters);
        printf("Error: All three values must be nonzero.\n");
        printArguments();
        return -1;
    }

    // Initialize the timer.
    time_t t0;
    time(&t0);

    // If specified, then convert to GDAL TIFF.
    char readFileName[1024];
    strcpy(readFileName, inputFileName);
    if (convert) {
        char cmd[4096];
        sprintf(readFileName, "temp.tif\0");
        sprintf(cmd, ".\\gdal\\gdal_translate %s temp.tif\n", inputFileName);
        system(cmd);
    }

    // Read DSM as SHORT.
    // Input can be GeoTIFF or LAS.
    shr3d::OrthoImage<unsigned short> dsmImage;
    shr3d::OrthoImage<unsigned short> minImage;
    printf("Reading DSM as SHORT.\n");
    int len = (int) strlen(inputFileName);
    char *ext = &inputFileName[len - 3];
    printf("File Type = .%s\n", ext);
    if (strcmp(ext, "tif") == 0) {
        bool ok = dsmImage.read(readFileName);
        if (!ok) return -1;
    } else if ((strcmp(ext, "las") == 0) || (strcmp(ext, "bpf") == 0)) {
        // First get the max Z values for the DSM.
        bool ok = dsmImage.readFromPointCloud(inputFileName, (float) dh_meters, shr3d::MAX_VALUE);
        if (!ok) return -1;

        // Median filter, replacing only points differing by more than the AGL threshold.
        dsmImage.medianFilter(1, (unsigned int) (agl_meters / dsmImage.scale));

        // Fill small voids in the DSM.
        dsmImage.fillVoidsPyramid(true, 2);

        // Write the DSM image as FLOAT.
        char dsmOutFileName[1024];
        sprintf(dsmOutFileName, "%s_DSM.tif\0", inputFileName);
        dsmImage.write(dsmOutFileName, true);

        // Now get the minimum Z values for the DTM.
        ok = minImage.readFromPointCloud(inputFileName, (float) dh_meters, shr3d::MIN_VALUE);
        if (!ok) return -1;

        // Median filter, replacing only points differing by more than the AGL threshold.
        minImage.medianFilter(1, (unsigned int) (agl_meters / minImage.scale));

        // Fill small voids in the DSM.
        minImage.fillVoidsPyramid(true, 2);

        // Write the MIN image as FLOAT.
        char minOutFileName[1024];
        sprintf(minOutFileName, "%s_MIN.tif\0", inputFileName);
        minImage.write(minOutFileName, true);

        // Find many of the trees by comparing MIN and MAX. Set their values to void.
        for (int j = 0; j < dsmImage.height; j++) {
            for (int i = 0; i < dsmImage.width; i++) {
                float minValue = (float) minImage.data[j][i];

                // This check is to avoid penalizing spurious returns under very tall buildings.
                // CAUTION: This is a hack to address an observed lidar sensor issue and may not generalize well.
                if (((float) dsmImage.data[j][i] - minValue) < (40.0 / minImage.scale)) {
                    // If this is in the trees, then set to void.
                    bool found = false;
                    double threshold = dz_meters / dsmImage.scale;
                    int i1 = MAX(0, i - 1);
                    int i2 = MIN(i + 1, dsmImage.width - 1);
                    int j1 = MAX(0, j - 1);
                    int j2 = MIN(j + 1, dsmImage.height - 1);
                    for (int jj = j1; jj <= j2; jj++) {
                        for (int ii = i1; ii <= i2; ii++) {
                            float diff = (float) dsmImage.data[jj][ii] - minValue;
                            if (diff < threshold) found = true;
                        }
                    }
                    if (!found) dsmImage.data[j][i] = 0;
                }
            }
        }

        // Write the DSM2 image as FLOAT.
        char dsm2OutFileName[1024];
        sprintf(dsm2OutFileName, "%s_DSM2.tif\0", inputFileName);
        dsmImage.write(dsm2OutFileName, true);
    } else {
        printf("Error: Unrecognized file type.");
        return -1;
    }

    // Convert horizontal and vertical uncertainty values to bin units.
    int dh_bins = MAX(1, (int) floor(dh_meters / dsmImage.gsd));
    printf("DZ_METERS = %f\n", dz_meters);
    printf("DH_METERS = %f\n", dh_meters);
    printf("DH_BINS = %d\n", dh_bins);
    unsigned int dz_short = (unsigned int) (dz_meters / dsmImage.scale);
    printf("DZ_SHORT = %d\n", dz_short);
    printf("AGL_METERS = %f\n", agl_meters);
    unsigned int agl_short = (unsigned int) (agl_meters / dsmImage.scale);
    printf("AGL_SHORT = %d\n", agl_short);
    printf("AREA_METERS = %f\n", min_area_meters);

    // Generate label image.
    shr3d::OrthoImage<unsigned long> labelImage;
    labelImage.Allocate(dsmImage.width, dsmImage.height);
    labelImage.easting = dsmImage.easting;
    labelImage.northing = dsmImage.northing;
    labelImage.zone = dsmImage.zone;
    labelImage.gsd = dsmImage.gsd;

    // Allocate a DTM image as SHORT and copy in the DSM values.
    shr3d::OrthoImage<unsigned short> dtmImage;
    dtmImage.Allocate(dsmImage.width, dsmImage.height);
    dtmImage.easting = dsmImage.easting;
    dtmImage.northing = dsmImage.northing;
    dtmImage.zone = dsmImage.zone;
    dtmImage.gsd = dsmImage.gsd;
    dtmImage.scale = dsmImage.scale;
    dtmImage.offset = dsmImage.offset;
    dtmImage.bands = dsmImage.bands;
    for (int j = 0; j < dsmImage.height; j++) {
        for (int i = 0; i < dsmImage.width; i++) {
            dtmImage.data[j][i] = minImage.data[j][i];
        }
    }

    // Classify ground points.
    shr3d::Shr3dder::classifyGround(labelImage, dsmImage, dtmImage, dh_bins, dz_short);

    // For DSM voids, also set DTM value to void.
    printf("Setting DTM values to VOID where DSM is VOID...\n");
    for (int j = 0; j < dsmImage.height; j++) {
        for (int i = 0; i < dsmImage.width; i++) {
            if (dsmImage.data[j][i] == 0) dtmImage.data[j][i] = 0;
        }
    }

    // Median filter, replacing only points differing by more than the DZ threshold.
    dtmImage.medianFilter(1, (unsigned int) (dz_meters / dsmImage.scale));

    // Refine the object label image and export building outlines.
    shr3d::Shr3dder::classifyNonGround(dsmImage, dtmImage, labelImage, dz_short, agl_short, (float) min_area_meters);

    // Fill small voids in the DTM after all processing is complete.
    dtmImage.fillVoidsPyramid(true, 2);

    // Write the DTM image as FLOAT.
    char dtmOutFileName[1024];
    sprintf(dtmOutFileName, "%s_DTM.tif\0", inputFileName);
    dtmImage.write(dtmOutFileName, true, egm96);

    // Produce a classification raster image with LAS standard point classes.
    shr3d::OrthoImage<unsigned char> classImage;
    classImage.Allocate(labelImage.width, labelImage.height);
    classImage.easting = dsmImage.easting;
    classImage.northing = dsmImage.northing;
    classImage.zone = dsmImage.zone;
    classImage.gsd = dsmImage.gsd;
    for (int j = 0; j < classImage.height; j++) {
        for (int i = 0; i < classImage.width; i++) {
            // Set default as unlabeled.
            classImage.data[j][i] = LAS_UNCLASSIFIED;

            // Label trees.
            if ((dsmImage.data[j][i] == 0) ||
                (fabs((float) dsmImage.data[j][i] - (float) dtmImage.data[j][i]) > agl_short))
                classImage.data[j][i] = LAS_TREE;

            // Label buildings.
            if (labelImage.data[j][i] == 1) classImage.data[j][i] = LAS_BUILDING;

            // Label ground.
            if (fabs((float) dsmImage.data[j][i] - (float) dtmImage.data[j][i]) < dz_short)
                classImage.data[j][i] = LAS_GROUND;
        }
    }

    // Fill missing labels inside building regions.
    shr3d::Shr3dder::fillInsideBuildings(classImage);

    // Write the classification image.
    char classOutFileName[1024];
    sprintf(classOutFileName, "%s_class.tif\0", inputFileName);
    classImage.write(classOutFileName, false, egm96);
    for (int j = 0; j < classImage.height; j++) {
        for (int i = 0; i < classImage.width; i++) {
            if (classImage.data[j][i] != LAS_BUILDING) classImage.data[j][i] = 0;
        }
    }
    sprintf(classOutFileName, "%s_buildings.tif\0", inputFileName);
    classImage.write(classOutFileName, false, egm96);

    // Report total elapsed time.
    time_t t1;
    time(&t1);
    printf("Total time elapsed = %f seconds\n", double(t1 - t0));
}

<|endoftext|>