<commit_before>#ifndef TSW_HEADER_INCLUDED
#define TSW_HEADER_INCLUDED
/**
  * (T)hread-(S)afe cached data (W)riter for C++ 11
  *
  * Copyright (c) 2015 Jan Pipek (MIT licence)
  *
  * This file can be used as is without external dependencies,
  * see https://github.com/janpipek/tsw .
  */

// Some hacking to make this work in various gcc older versions
#if __GNUG__ && !defined(__clang_major__)
    #if __GNUG__ < 4 || (__GNUG__ == 4 && __GNUC_MINOR < 4)
        #error Only supported in gcc >= 4.4
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 5)
        #define noexcept
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 6)
        #define constexpr const
        #define nullptr 0   // Good style but necessary
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 7)
        #define override    // Good style but necessary
    #endif
#endif

#include <tuple>
#include <vector>
#include <iostream>
#include <utility>
#include <array>
#include <fstream>
#include <iomanip>
#include <memory>
#include <stdexcept>

// Enable explicitely not to use standard thread API (question is if it has any sense...)
#ifdef TSW_USE_POSIX_THREADS
    #include <pthread.h>
    #define TSW_MUTEX_DECLARATION pthread_mutex_t _mutex
    #define TSW_MUTEX_INITIALIZATION pthread_mutexattr_t attr;\
        pthread_mutexattr_init(&attr);\
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
        pthread_mutex_init(&_mutex, &attr)
    #define TSW_LOCK bool ok = true;\
        pthread_mutex_lock(&_mutex);\
        try {
    #define TSW_UNLOCK } \
        catch(...) { ok = false; }\
        pthread_mutex_unlock(&_mutex);\
        if (!ok) {\
            throw std::runtime_error("Error in threaded writing");\
        }
#else
    #ifdef TSW_NO_THREADS
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION
        #define TSW_LOCK
        #define TSW_UNLOCK
    #else
        #define TSW_USE_CPPT11_THREADS
        #include <mutex>
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION std::recursive_mutex _mutex
        #define TSW_LOCK { std::lock_guard<std::recursive_mutex> lock(_mutex)
        #define TSW_UNLOCK }
    #endif
#endif

namespace tsw
{
    /**
      * @short Base class of all thread safe writers.
      *
      * The implementation is defined using templates (including most methods)
      * Only non-templated abstract methods can be declared (as interface) here.
      */
    class ThreadSafeWriter
    {
    public:
        /**
          * @short Set how many rows will be cached at maximum
          *        before the flushing is forced.
          */
        virtual void SetCacheCapacity(size_t capacity) = 0;

        virtual bool IsFlushRequired() const = 0;

        /**
          * @short This method forces data to be written to the file.
          *
          * Automatically triggered when the cache is full and in the destructor.
          */
        virtual void Flush() = 0;

        virtual ~ThreadSafeWriter() = default;     // Enable polymorphism

        virtual size_t GetItemsStored() const noexcept = 0;

        virtual size_t GetItemsWritten() const noexcept = 0;
    };

    template <class... Ts> class BaseThreadSafeWriter : public ThreadSafeWriter { };

    /**
      * @short Base templated class implementing the cache and thread-safety.
      *
      * The particular method for writing is to be implemented in child classes.
      */
    template <class U, class... Ts> class BaseThreadSafeWriter<U, Ts...> : public BaseThreadSafeWriter<>
    {
    public:
        BaseThreadSafeWriter() : _columnNames(), _cacheCapacity(1000), _itemsStored(0), _itemsWritten(0)
        {
            TSW_MUTEX_INITIALIZATION;
        }

        constexpr static size_t itemDim = sizeof...(Ts) + 1;

        typedef std::array<std::string, itemDim> nameCollectionT;

        typedef std::tuple<U, Ts...> itemT;

        void SetColumnNames(const nameCollectionT& columnNames)
        {
            TSW_LOCK;
            if (_itemsStored)
            {
                throw std::runtime_error("Cannot change column names after items were already written.");
            }
            _columnNames.reset(new nameCollectionT(columnNames));
            TSW_UNLOCK;
        }

        template <class... Vs> void SetColumnNames(const std::string& name1, const Vs&... names)
        {
            static_assert(sizeof...(Vs) == (itemDim - 1), "Column names must be of the same dimension as data.");

            TSW_LOCK;
            if (_itemsStored)
            {
                throw std::runtime_error("Cannot change column names after items were already written.");
            }
            auto temp = nameCollectionT{name1, names...};
            _columnNames.reset(new nameCollectionT(temp));
            TSW_UNLOCK;
        }

        void Store(const itemT& item)
        {
            TSW_LOCK;
            _data.push_back(item);
            if (IsFlushRequired())
            {
                Flush();
            }
            _itemsStored++;
            TSW_UNLOCK;
        }

        void Store(const U& first, const Ts&... args)
        {
            Store(std::make_tuple(first, args...));
        }

        bool IsFlushRequired() const override
        {
            return _data.size() == _cacheCapacity;
        }

        void SetCacheCapacity(size_t capacity) override
        {
            TSW_LOCK;
            _cacheCapacity = capacity;
            if (IsFlushRequired())
            {
                Flush();
            }
            else
            {
                _data.reserve(_cacheCapacity);
            }
            TSW_UNLOCK;
        }

        void Flush() override
        {
            TSW_LOCK;
            StartFlush();
            int localWritten = 0;
            for (auto item = _data.begin(); item != _data.end(); item++)
            {
            // for (auto item : _data) {
                Write(*item);
                localWritten++;
            }
            _itemsWritten += localWritten;
            FinishFlush();
            _data.clear();
            _data.reserve(_cacheCapacity);
            TSW_UNLOCK;
        }

        virtual size_t GetItemsStored() const noexcept override { return _itemsStored; }

        virtual size_t GetItemsWritten() const noexcept override { return _itemsWritten; }

    protected:
        virtual void StartFlush() { }

        virtual void FinishFlush() { }

        virtual void Write(const std::tuple<U, Ts...>& item) = 0;

        size_t _cacheCapacity;

        size_t _itemsStored;

        size_t _itemsWritten;

        std::vector<itemT> _data;

        TSW_MUTEX_DECLARATION;

        std::unique_ptr<nameCollectionT> _columnNames;
    };

    template <class... Ts> class TSVWriter : public BaseThreadSafeWriter<> { };

    /**
      * @short Writer for tabular text formats (TSV, CSV, ...)
      *
      * The default variant uses \n for line separation, \t for column separation.
      *
      * Warning: strings are not escaped in any way
      */
    template <class U, class... Ts> class TSVWriter<U, Ts...> : public BaseThreadSafeWriter<U, Ts...>
    {
    protected:
        using BaseThreadSafeWriter<U, Ts...>::_columnNames;

        using BaseThreadSafeWriter<U, Ts...>::Flush;

    public:
        using BaseThreadSafeWriter<U, Ts...>::itemDim;

        TSVWriter(const std::string& fileName) : _opened(false), _fileName(fileName), _stream(),
            _columnSeparator("\t"), _lineSeparator("\n"), _precision(6)
        {
        }

        TSVWriter(const TSVWriter& other) = delete;

        TSVWriter& operator=(const TSVWriter& other) = delete;

        virtual ~TSVWriter()
        {
            Flush();
            if (_opened)
            {
                _stream->close();
            }
        }

        void SetColumnSeparator(const std::string& sep)
        {
            _columnSeparator = sep;
        }

        void SetLineSeparator(const std::string& sep)
        {
            _lineSeparator = sep;
        }

        void SetPrecision(int digits)
        {
            _precision = digits;
            if (_opened)
            {
                (*_stream) << std::setprecision(_precision);
            }
        }

    protected:
        void Open()
        {
            _stream.reset(new std::ofstream(_fileName));
            (*_stream) << std::setprecision(_precision);
            if (_columnNames)
            {
                for (size_t i = 0; i < itemDim - 1; i++)
                {
                    *_stream << (*_columnNames)[i] << _columnSeparator;
                }
                *_stream << (*_columnNames)[itemDim - 1] << _lineSeparator;
                _stream->flush();
            }
            _opened = true;
        }

        bool _opened;

        std::string _fileName;

        std::unique_ptr<std::ofstream> _stream;

        std::string _columnSeparator;

        std::string _lineSeparator;

        int _precision;

        void StartFlush() override
        {
            if (!_opened)
            {
                Open();
            }
        }

        void FinishFlush() override
        {
            _stream->flush();
        }

        void Write(const std::tuple<U, Ts...>& item) override
        {
            WriteItem(item);
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I == sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>&)
        {
            *_stream << _lineSeparator;
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I < sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << std::get<I>(t) << _columnSeparator;
            WriteItem<I + 1, Vs...>(t);
        }
    };
}
#endif<commit_msg>using keyword instead of typedef<commit_after>#ifndef TSW_HEADER_INCLUDED
#define TSW_HEADER_INCLUDED
/**
  * (T)hread-(S)afe cached data (W)riter for C++ 11
  *
  * Copyright (c) 2015 Jan Pipek (MIT licence)
  *
  * This file can be used as is without external dependencies,
  * see https://github.com/janpipek/tsw .
  */

// Some hacking to make this work in various gcc older versions
#if __GNUG__ && !defined(__clang_major__)
    #if __GNUG__ < 4 || (__GNUG__ == 4 && __GNUC_MINOR < 4)
        #error Only supported in gcc >= 4.4
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 5)
        #define noexcept
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 6)
        #define constexpr const
        #define nullptr 0   // Good style but necessary
    #endif
    #if (__GNUG__ == 4 && __GNUC_MINOR < 7)
        #define override    // Good style but necessary
    #endif
#endif

#include <tuple>
#include <vector>
#include <iostream>
#include <utility>
#include <array>
#include <fstream>
#include <iomanip>
#include <memory>
#include <stdexcept>

// Enable explicitely not to use standard thread API (question is if it has any sense...)
#ifdef TSW_USE_POSIX_THREADS
    #include <pthread.h>
    #define TSW_MUTEX_DECLARATION pthread_mutex_t _mutex
    #define TSW_MUTEX_INITIALIZATION pthread_mutexattr_t attr;\
        pthread_mutexattr_init(&attr);\
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
        pthread_mutex_init(&_mutex, &attr)
    #define TSW_LOCK bool ok = true;\
        pthread_mutex_lock(&_mutex);\
        try {
    #define TSW_UNLOCK } \
        catch(...) { ok = false; }\
        pthread_mutex_unlock(&_mutex);\
        if (!ok) {\
            throw std::runtime_error("Error in threaded writing");\
        }
#else
    #ifdef TSW_NO_THREADS
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION
        #define TSW_LOCK
        #define TSW_UNLOCK
    #else
        #define TSW_USE_CPPT11_THREADS
        #include <mutex>
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION std::recursive_mutex _mutex
        #define TSW_LOCK { std::lock_guard<std::recursive_mutex> lock(_mutex)
        #define TSW_UNLOCK }
    #endif
#endif

namespace tsw
{
    /**
      * @short Base class of all thread safe writers.
      *
      * The implementation is defined using templates (including most methods)
      * Only non-templated abstract methods can be declared (as interface) here.
      */
    class ThreadSafeWriter
    {
    public:
        /**
          * @short Set how many rows will be cached at maximum
          *        before the flushing is forced.
          */
        virtual void SetCacheCapacity(size_t capacity) = 0;

        virtual bool IsFlushRequired() const = 0;

        /**
          * @short This method forces data to be written to the file.
          *
          * Automatically triggered when the cache is full and in the destructor.
          */
        virtual void Flush() = 0;

        virtual ~ThreadSafeWriter() = default;     // Enable polymorphism

        virtual size_t GetItemsStored() const noexcept = 0;

        virtual size_t GetItemsWritten() const noexcept = 0;
    };

    template <class... Ts> class BaseThreadSafeWriter : public ThreadSafeWriter { };

    /**
      * @short Base templated class implementing the cache and thread-safety.
      *
      * The particular method for writing is to be implemented in child classes.
      */
    template <class U, class... Ts> class BaseThreadSafeWriter<U, Ts...> : public BaseThreadSafeWriter<>
    {
    public:
        BaseThreadSafeWriter() : _columnNames(), _cacheCapacity(1000), _itemsStored(0), _itemsWritten(0)
        {
            TSW_MUTEX_INITIALIZATION;
        }

        constexpr static size_t itemDim = sizeof...(Ts) + 1;

        using nameCollectionT = std::array<std::string, itemDim>;

        using itemT = std::tuple<U, Ts...>;

        void SetColumnNames(const nameCollectionT& columnNames)
        {
            TSW_LOCK;
            if (_itemsStored)
            {
                throw std::runtime_error("Cannot change column names after items were already written.");
            }
            _columnNames.reset(new nameCollectionT(columnNames));
            TSW_UNLOCK;
        }

        template <class... Vs> void SetColumnNames(const std::string& name1, const Vs&... names)
        {
            static_assert(sizeof...(Vs) == (itemDim - 1), "Column names must be of the same dimension as data.");

            TSW_LOCK;
            if (_itemsStored)
            {
                throw std::runtime_error("Cannot change column names after items were already written.");
            }
            auto temp = nameCollectionT{name1, names...};
            _columnNames.reset(new nameCollectionT(temp));
            TSW_UNLOCK;
        }

        void Store(const itemT& item)
        {
            TSW_LOCK;
            _data.push_back(item);
            if (IsFlushRequired())
            {
                Flush();
            }
            _itemsStored++;
            TSW_UNLOCK;
        }

        void Store(const U& first, const Ts&... args)
        {
            Store(std::make_tuple(first, args...));
        }

        bool IsFlushRequired() const override
        {
            return _data.size() == _cacheCapacity;
        }

        void SetCacheCapacity(size_t capacity) override
        {
            TSW_LOCK;
            _cacheCapacity = capacity;
            if (IsFlushRequired())
            {
                Flush();
            }
            else
            {
                _data.reserve(_cacheCapacity);
            }
            TSW_UNLOCK;
        }

        void Flush() override
        {
            TSW_LOCK;
            StartFlush();
            int localWritten = 0;
            for (auto item = _data.begin(); item != _data.end(); item++)
            {
            // for (auto item : _data) {
                Write(*item);
                localWritten++;
            }
            _itemsWritten += localWritten;
            FinishFlush();
            _data.clear();
            _data.reserve(_cacheCapacity);
            TSW_UNLOCK;
        }

        virtual size_t GetItemsStored() const noexcept override { return _itemsStored; }

        virtual size_t GetItemsWritten() const noexcept override { return _itemsWritten; }

    protected:
        virtual void StartFlush() { }

        virtual void FinishFlush() { }

        virtual void Write(const std::tuple<U, Ts...>& item) = 0;

        size_t _cacheCapacity;

        size_t _itemsStored;

        size_t _itemsWritten;

        std::vector<itemT> _data;

        TSW_MUTEX_DECLARATION;

        std::unique_ptr<nameCollectionT> _columnNames;
    };

    template <class... Ts> class TSVWriter : public BaseThreadSafeWriter<> { };

    /**
      * @short Writer for tabular text formats (TSV, CSV, ...)
      *
      * The default variant uses \n for line separation, \t for column separation.
      *
      * Warning: strings are not escaped in any way
      */
    template <class U, class... Ts> class TSVWriter<U, Ts...> : public BaseThreadSafeWriter<U, Ts...>
    {
    protected:
        using BaseThreadSafeWriter<U, Ts...>::_columnNames;

        using BaseThreadSafeWriter<U, Ts...>::Flush;

    public:
        using BaseThreadSafeWriter<U, Ts...>::itemDim;

        TSVWriter(const std::string& fileName) : _opened(false), _fileName(fileName), _stream(),
            _columnSeparator("\t"), _lineSeparator("\n"), _precision(6)
        {
        }

        TSVWriter(const TSVWriter& other) = delete;

        TSVWriter& operator=(const TSVWriter& other) = delete;

        virtual ~TSVWriter()
        {
            Flush();
            if (_opened)
            {
                _stream->close();
            }
        }

        void SetColumnSeparator(const std::string& sep)
        {
            _columnSeparator = sep;
        }

        void SetLineSeparator(const std::string& sep)
        {
            _lineSeparator = sep;
        }

        void SetPrecision(int digits)
        {
            _precision = digits;
            if (_opened)
            {
                (*_stream) << std::setprecision(_precision);
            }
        }

    protected:
        void Open()
        {
            _stream.reset(new std::ofstream(_fileName));
            (*_stream) << std::setprecision(_precision);
            if (_columnNames)
            {
                for (size_t i = 0; i < itemDim - 1; i++)
                {
                    *_stream << (*_columnNames)[i] << _columnSeparator;
                }
                *_stream << (*_columnNames)[itemDim - 1] << _lineSeparator;
                _stream->flush();
            }
            _opened = true;
        }

        bool _opened;

        std::string _fileName;

        std::unique_ptr<std::ofstream> _stream;

        std::string _columnSeparator;

        std::string _lineSeparator;

        int _precision;

        void StartFlush() override
        {
            if (!_opened)
            {
                Open();
            }
        }

        void FinishFlush() override
        {
            _stream->flush();
        }

        void Write(const std::tuple<U, Ts...>& item) override
        {
            WriteItem(item);
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I == sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>&)
        {
            *_stream << _lineSeparator;
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I < sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << std::get<I>(t) << _columnSeparator;
            WriteItem<I + 1, Vs...>(t);
        }
    };
}
#endif
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QtGlobal>

#if defined(Q_OS_WIN32)
#  include <windows.h>
#elif defined(Q_OS_UNIX)
#  include <sys/stat.h>
#  include <utime.h>
#endif

#include <QDateTime>

#include "file.h"

File::File(const QString &root, const QVariantMap &properties)
{
    mRelativeFilename = properties.value("name").toString();

    // Create the full path by combining the root with the relative filename
    mFile.setFileName(QDir::cleanPath(root + QDir::separator() + mRelativeFilename));

    mSize = properties.value("size").toLongLong();
    mReadOnly = properties.value("read_only").toBool();
    mExecutable = properties.value("executable").toBool();

    mCreated = properties.value("created").toInt();
    mLastRead = properties.value("last_read").toInt();
    mLastModified = properties.value("last_modified").toInt();
}

File::File(const QDir &root, const QFileInfo &info, int blockSize)
{
    mFile.setFileName(info.absoluteFilePath());
    mBlockSize = blockSize;

    mRelativeFilename = root.relativeFilePath(info.absoluteFilePath());

    mSize = info.size();
    mReadOnly = !info.isWritable();
    mExecutable = info.isExecutable();

    mCreated = info.created().toMSecsSinceEpoch();
    mLastRead = info.lastRead().toMSecsSinceEpoch();
    mLastModified = info.lastModified().toMSecsSinceEpoch();
}

bool File::readOnly() const
{
    return mReadOnly;
}

bool File::executable() const
{
    return mExecutable;
}

qint64 File::created() const
{
    return mCreated;
}

qint64 File::lastRead() const
{
    return mLastRead;
}

qint64 File::lastModified() const
{
    return mLastModified;
}

qint64 File::last_read() const
{
    return mLastRead;
}

qint64 File::last_modified() const
{
    return mLastModified;
}

QString File::type() const
{
    return "file";
}

QString File::name() const
{
    return mRelativeFilename;
}

qint64 File::size() const
{
    return mSize;
}

bool File::open(OpenMode openMode)
{
    if (openMode == Write && !QDir(QFileInfo(mFile.fileName()).absolutePath()).mkpath(".")) {
        return false;
    }
    return mFile.open(openMode == Read ? QIODevice::ReadOnly : QIODevice::WriteOnly);
}

QByteArray File::read()
{
    // Allocate a full block and then resize to actual data length
    QByteArray data;
    data.resize(mBlockSize);
    qint64 bytesRead = mFile.read(data.data(), mBlockSize);
    data.resize(bytesRead);

    if (bytesRead == -1) {
        emit error(mFile.errorString());
    }

    return data;
}

void File::write(const QByteArray &data)
{
    if (mFile.write(data) == -1) {
        emit error(mFile.errorString());
    }
}

#ifdef Q_OS_WIN32

// Adapted from https://support.microsoft.com/en-us/help/167296
void unixTimestampMsToFiletime(qint64 timestampMs, LPFILETIME pft)
{
    // Convert from MS to 100-nanosecond intervals
    quint64 ll = timestampMs * 10000;

    // Assign to members of FILETIME struct
    pft->dwLowDateTime = (DWORD)ll;
    pft->dwHighDateTime = ll >> 32;
}

#endif

void File::close()
{
    mFile.close();

#if defined(Q_OS_WIN32)

    FILETIME createdFiletime;
    FILETIME lastReadFiletime;
    FILETIME lastModifiedFiletime;

    // Perform the conversions
    unixTimestampMsToFiletime(mCreated, &createdFiletime);
    unixTimestampMsToFiletime(mLastRead, &lastReadFiletime);
    unixTimestampMsToFiletime(mLastModified, &lastModifiedFiletime);

    // Open the file
    HANDLE hFile = CreateFileW(
        reinterpret_cast<LPCWSTR>(mFile.fileName().utf16()),
        GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        // TODO: throw an error
        return;
    }

    // Set the attributes
    BOOL succeeded = SetFileTime(
        hFile,
        mCreated ? &createdFiletime : NULL,
        mLastRead ? &lastReadFiletime : NULL,
        mLastModified ? &lastModifiedFiletime : NULL
    );
    if (succeeded == FALSE) {
        // TODO: throw an error
    }

    CloseHandle(hFile);

#elif defined(Q_OS_UNIX)

    // Retrieve existing statistics
    struct stat oldStats;
    if (stat(mFile.fileName().toUtf8(), &oldStats)) {
        // TODO: throw error
        return;
    }

    // Create the struct with the new values
    struct utimbuf newTimes;
    newTimes.actime = mLastRead ? mLastRead / 1000 : oldStats.st_atim.tv_sec;
    newTimes.modtime = mLastModified ? mLastModified / 1000 : oldStats.st_mtim.tv_sec;

    // Set the new values
    if (utime(mFile.fileName().toUtf8(), &newTimes)) {
        // TODO: throw error
    }

#endif
}
<commit_msg>Change a couple of parameters for CreateFile.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QtGlobal>

#if defined(Q_OS_WIN32)
#  include <windows.h>
#elif defined(Q_OS_UNIX)
#  include <sys/stat.h>
#  include <utime.h>
#endif

#include <QDateTime>

#include "file.h"

File::File(const QString &root, const QVariantMap &properties)
{
    mRelativeFilename = properties.value("name").toString();

    // Create the full path by combining the root with the relative filename
    mFile.setFileName(QDir::cleanPath(root + QDir::separator() + mRelativeFilename));

    mSize = properties.value("size").toLongLong();
    mReadOnly = properties.value("read_only").toBool();
    mExecutable = properties.value("executable").toBool();

    mCreated = properties.value("created").toInt();
    mLastRead = properties.value("last_read").toInt();
    mLastModified = properties.value("last_modified").toInt();
}

File::File(const QDir &root, const QFileInfo &info, int blockSize)
{
    mFile.setFileName(info.absoluteFilePath());
    mBlockSize = blockSize;

    mRelativeFilename = root.relativeFilePath(info.absoluteFilePath());

    mSize = info.size();
    mReadOnly = !info.isWritable();
    mExecutable = info.isExecutable();

    mCreated = info.created().toMSecsSinceEpoch();
    mLastRead = info.lastRead().toMSecsSinceEpoch();
    mLastModified = info.lastModified().toMSecsSinceEpoch();
}

bool File::readOnly() const
{
    return mReadOnly;
}

bool File::executable() const
{
    return mExecutable;
}

qint64 File::created() const
{
    return mCreated;
}

qint64 File::lastRead() const
{
    return mLastRead;
}

qint64 File::lastModified() const
{
    return mLastModified;
}

qint64 File::last_read() const
{
    return mLastRead;
}

qint64 File::last_modified() const
{
    return mLastModified;
}

QString File::type() const
{
    return "file";
}

QString File::name() const
{
    return mRelativeFilename;
}

qint64 File::size() const
{
    return mSize;
}

bool File::open(OpenMode openMode)
{
    if (openMode == Write && !QDir(QFileInfo(mFile.fileName()).absolutePath()).mkpath(".")) {
        return false;
    }
    return mFile.open(openMode == Read ? QIODevice::ReadOnly : QIODevice::WriteOnly);
}

QByteArray File::read()
{
    // Allocate a full block and then resize to actual data length
    QByteArray data;
    data.resize(mBlockSize);
    qint64 bytesRead = mFile.read(data.data(), mBlockSize);
    data.resize(bytesRead);

    if (bytesRead == -1) {
        emit error(mFile.errorString());
    }

    return data;
}

void File::write(const QByteArray &data)
{
    if (mFile.write(data) == -1) {
        emit error(mFile.errorString());
    }
}

#ifdef Q_OS_WIN32

// Adapted from https://support.microsoft.com/en-us/help/167296
void unixTimestampMsToFiletime(qint64 timestampMs, LPFILETIME pft)
{
    // Convert from MS to 100-nanosecond intervals
    quint64 ll = timestampMs * 10000;

    // Assign to members of FILETIME struct
    pft->dwLowDateTime = (DWORD)ll;
    pft->dwHighDateTime = ll >> 32;
}

#endif

void File::close()
{
    mFile.close();

#if defined(Q_OS_WIN32)

    FILETIME createdFiletime;
    FILETIME lastReadFiletime;
    FILETIME lastModifiedFiletime;

    // Perform the conversions
    unixTimestampMsToFiletime(mCreated, &createdFiletime);
    unixTimestampMsToFiletime(mLastRead, &lastReadFiletime);
    unixTimestampMsToFiletime(mLastModified, &lastModifiedFiletime);

    // Open the file
    HANDLE hFile = CreateFileW(
        reinterpret_cast<LPCWSTR>(mFile.fileName().utf16()),
        GENERIC_READ | FILE_WRITE_ATTRIBUTES,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        // TODO: throw an error
        return;
    }

    // Set the attributes
    BOOL succeeded = SetFileTime(
        hFile,
        mCreated ? &createdFiletime : NULL,
        mLastRead ? &lastReadFiletime : NULL,
        mLastModified ? &lastModifiedFiletime : NULL
    );
    if (succeeded == FALSE) {
        // TODO: throw an error
    }

    CloseHandle(hFile);

#elif defined(Q_OS_UNIX)

    // Retrieve existing statistics
    struct stat oldStats;
    if (stat(mFile.fileName().toUtf8(), &oldStats)) {
        // TODO: throw error
        return;
    }

    // Create the struct with the new values
    struct utimbuf newTimes;
    newTimes.actime = mLastRead ? mLastRead / 1000 : oldStats.st_atim.tv_sec;
    newTimes.modtime = mLastModified ? mLastModified / 1000 : oldStats.st_mtim.tv_sec;

    // Set the new values
    if (utime(mFile.fileName().toUtf8(), &newTimes)) {
        // TODO: throw error
    }

#endif
}
<|endoftext|>


<commit_before>#ifndef UNICODE
#define UNICODE
#endif

#include "Headers.h"

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void initDevice(DXGI_SWAP_CHAIN_DESC&, HWND&);
HRESULT createDevice(D3D_FEATURE_LEVEL&, DXGI_SWAP_CHAIN_DESC&, IDXGISwapChain*, ID3D11Device*, D3D_FEATURE_LEVEL&, ID3D11DeviceContext*);
HRESULT initRTV(ID3D11RenderTargetView *, ID3D11Texture2D *);
void Render();

IDXGISwapChain* ppSwapChain = NULL;
ID3D11Device* ppDevice = NULL;
D3D_FEATURE_LEVEL FeatureLevel;
ID3D11DeviceContext* ppImmediateContext = NULL;
ID3D11RenderTargetView* pRenderTargetView = NULL;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	// Register the window class.
	const wchar_t CLASS_NAME[] = L"TMSG";

	WNDCLASS wc = {};
	DXGI_SWAP_CHAIN_DESC sd;
	D3D_FEATURE_LEVEL FeatureLevels = D3D_FEATURE_LEVEL_11_0;
	ID3D11Texture2D *backBuf = NULL;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = CLASS_NAME;

	RegisterClass(&wc);

	// Create the window.

	HWND hwnd = CreateWindowEx(
		0,                              // Optional window styles.
		CLASS_NAME,                     // Window class
		L"TMSG",    // Window text
		WS_OVERLAPPEDWINDOW,            // Window style

										// Size and position
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,

		NULL,       // Parent window
		NULL,       // Menu
		hInstance,  // Instance handle
		NULL        // Additional application data
	);

	if (hwnd == NULL)
	{
		return 0;
	}

	initDevice(sd, hwnd);
	if (ERROR == createDevice(FeatureLevels, sd, ppSwapChain, ppDevice, FeatureLevel, ppImmediateContext)) {
		MessageBox(hwnd, L"CREATEDEVICE ERROR!!", L"ERROR", MB_OK);
		return 0;
	}
	if (ERROR == initRTV(pRenderTargetView, backBuf)) {
		MessageBox(hwnd, L"RENDERTAGETVIEW ERROR!!", L"ERROR", MB_OK);
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);

	// Run the message loop.

	MSG msg = {};
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			//Render();
		}
	}

	return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	case WM_PAINT:
		PAINTSTRUCT ps;
		HDC hdc;
		hdc = BeginPaint(hwnd, &ps);
		EndPaint(hwnd, &ps);
		return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void initDevice(DXGI_SWAP_CHAIN_DESC& sd, HWND& hwnd) {
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferCount = 1;
	sd.BufferDesc.Width = 640;
	sd.BufferDesc.Height = 480;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = hwnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
}

HRESULT createDevice(
	D3D_FEATURE_LEVEL &FeatureLevels,
	DXGI_SWAP_CHAIN_DESC& sd,
	IDXGISwapChain* g_pSwapChain,
	ID3D11Device* g_pd3dDevice,
	D3D_FEATURE_LEVEL& FeatureLevel,
	ID3D11DeviceContext* g_pImmediateContext
) {
	HRESULT hr = S_OK;

	if (FAILED(hr = D3D11CreateDeviceAndSwapChain(NULL,
		D3D_DRIVER_TYPE_REFERENCE,
		NULL,
		0,
		&FeatureLevels,
		1,
		D3D11_SDK_VERSION,
		&sd,
		&g_pSwapChain,
		&g_pd3dDevice,
		&FeatureLevel,
		&g_pImmediateContext)))
	{
		hr = ERROR;
		return hr;
	}
	return hr;
}

HRESULT initRTV(ID3D11RenderTargetView *RTV, ID3D11Texture2D *backBuf) {
	HRESULT hr;
	if (FAILED(hr = ppSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
		reinterpret_cast<void**>(&backBuf)))) {
		hr = ERROR;
		return hr;
	}
	if (FAILED(hr = ppDevice->CreateRenderTargetView(backBuf, 0, &RTV))) {
		hr = ERROR;
		return hr;
	}
	backBuf->Release();
	return hr;
}

void Render()
{
	// Just clear the backbuffer
	float ClearColor[4] = { 1.0f, 5.0f, 1.0f, 0.0f }; //red,green,blue,alpha
	ppImmediateContext->ClearRenderTargetView(pRenderTargetView, ClearColor);
	ppSwapChain->Present(0, 0);
}<commit_msg>DX초기화 및 출력제어<commit_after>#ifndef UNICODE
#define UNICODE
#endif

#include "Headers.h"

#define CLIENTWIDTH 640
#define CLIENTHEIGHT 480

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void initDevice(DXGI_SWAP_CHAIN_DESC&, HWND&);
HRESULT createDevice(D3D_FEATURE_LEVEL&, DXGI_SWAP_CHAIN_DESC&, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL&, ID3D11DeviceContext**);
HRESULT initRTV(IDXGISwapChain*, ID3D11RenderTargetView **);
HRESULT depthStensilBufferandView(D3D11_TEXTURE2D_DESC *, ID3D11Texture2D*, ID3D11DepthStencilView*);
void makeView(D3D11_VIEWPORT *);
void Render();
void CleanupDevice();

IDXGISwapChain* ppSwapChain;
ID3D11Device* ppDevice;
ID3D11DeviceContext* ppImmediateContext;
ID3D11RenderTargetView* pRenderTargetView;
ID3D11Texture2D* pDepthStencilBuffer;
ID3D11DepthStencilView* pDepthStencilView;
D3D11_VIEWPORT vp;
D3D_FEATURE_LEVEL FeatureLevel;
D3D11_TEXTURE2D_DESC DepthStencilDesc;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
	// Register the window class.
	const wchar_t CLASS_NAME[] = L"TMSG";

	WNDCLASS wc = {};
	DXGI_SWAP_CHAIN_DESC sd;
	D3D_FEATURE_LEVEL FeatureLevels = D3D_FEATURE_LEVEL_11_0;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.lpszClassName = CLASS_NAME;

	RegisterClass(&wc);

	// Create the window.

	HWND hwnd = CreateWindowEx(
		0,                              // Optional window styles.
		CLASS_NAME,                     // Window class
		L"TMSG",    // Window text
		WS_OVERLAPPEDWINDOW,            // Window style

										// Size and position
		CW_USEDEFAULT, CW_USEDEFAULT, CLIENTWIDTH, CLIENTHEIGHT,

		NULL,       // Parent window
		NULL,       // Menu
		hInstance,  // Instance handle
		NULL        // Additional application data
	);

	if (hwnd == NULL)
	{
		return 0;
	}

	initDevice(sd, hwnd);
	if (E_FAIL == createDevice(FeatureLevels, sd, &ppSwapChain, &ppDevice, FeatureLevel, &ppImmediateContext)) {
		MessageBox(hwnd, L"CREATEDEVICE ERROR!!", L"ERROR", MB_OK);
		return 0;
	}
	if (E_FAIL == initRTV(ppSwapChain, &pRenderTargetView)) {
		MessageBox(hwnd, L"RENDERTAGETVIEW ERROR!!", L"ERROR", MB_OK);
		return 0;
	}

	if (E_FAIL == depthStensilBufferandView(&DepthStencilDesc, pDepthStencilBuffer, pDepthStencilView)) {
	MessageBox(hwnd, L"DEPTHSTENSIL ERROR!!", L"ERROR", MB_OK);
	return 0;
	}

	ppImmediateContext->OMSetRenderTargets(1, &pRenderTargetView, pDepthStencilView);
	ppImmediateContext->RSSetViewports(1, &vp);

	ShowWindow(hwnd, nCmdShow);

	// Run the message loop.

	MSG msg = {};
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();
		}
	}

	CleanupDevice();
	return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	case WM_PAINT:
		PAINTSTRUCT ps;
		HDC hdc;
		hdc = BeginPaint(hwnd, &ps);
		EndPaint(hwnd, &ps);
		return 0;

	case WM_LBUTTONDOWN:
		ppImmediateContext->ClearRenderTargetView(pRenderTargetView, (const FLOAT*)(&Colors::Red));
		ppSwapChain->Present(0, 0);
		return 0;

	case WM_RBUTTONDOWN:
		ppImmediateContext->ClearRenderTargetView(pRenderTargetView, (const FLOAT*)(&Colors::Blue));
		ppSwapChain->Present(0, 0);
		return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void initDevice(DXGI_SWAP_CHAIN_DESC& sd, HWND& hwnd) {
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferCount = 1;
	sd.BufferDesc.Width = CLIENTWIDTH;
	sd.BufferDesc.Height = CLIENTHEIGHT;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = hwnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
}

HRESULT createDevice(
	D3D_FEATURE_LEVEL &FeatureLevels,
	DXGI_SWAP_CHAIN_DESC& sd,
	IDXGISwapChain** g_pSwapChain,
	ID3D11Device** g_pd3dDevice,
	D3D_FEATURE_LEVEL& FeatureLevel,
	ID3D11DeviceContext** g_pImmediateContext
) {
	HRESULT hr = S_OK;

	if (FAILED(hr = D3D11CreateDeviceAndSwapChain(NULL,
		D3D_DRIVER_TYPE_REFERENCE,
		NULL,
		0,
		NULL,
		0,
		D3D11_SDK_VERSION,
		&sd,
		g_pSwapChain,
		g_pd3dDevice,
		&FeatureLevel,
		g_pImmediateContext)))
	{
		hr = ERROR;
		return hr;
	}
	return hr;
}

//initialize RenderTargetView
HRESULT initRTV(IDXGISwapChain *pSwapChain, ID3D11RenderTargetView **RTV) {
	HRESULT hr = S_OK;
	ID3D11Texture2D *backBuf;
	if (FAILED(hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
		reinterpret_cast<void**>(&backBuf)))) {
		hr = ERROR;
		return hr;
	}
	if (FAILED(hr = ppDevice->CreateRenderTargetView(backBuf, 0, &*RTV))) {
		hr = ERROR;
		return hr;
	}
	backBuf->Release();
	return hr;
}

//Make Depth-Stensil buffer and view
HRESULT depthStensilBufferandView(D3D11_TEXTURE2D_DESC *pdsd, ID3D11Texture2D* pdsb, ID3D11DepthStencilView* pdsv) {
	HRESULT hr = S_OK;
	pdsd->Width = 640;
	pdsd->Height = 480;
	pdsd->MipLevels = 1;
	pdsd->ArraySize = 1;
	pdsd->Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	pdsd->SampleDesc.Count = 1;
	pdsd->SampleDesc.Quality = 0;
	pdsd->Usage = D3D11_USAGE_DEFAULT;
	pdsd->BindFlags = D3D11_BIND_DEPTH_STENCIL;
	pdsd->CPUAccessFlags = 0;
	pdsd->MipLevels = 0;
	if (FAILED(hr = ppDevice->CreateTexture2D(pdsd, 0, &pdsb))) {
		hr = ERROR;
		return hr;
	}
	if (FAILED(hr = ppDevice->CreateDepthStencilView(pdsb, 0, &pdsv))) {
		hr = ERROR;
		return hr;
	}
	return hr;
}

//Make Viewport
void makeView(D3D11_VIEWPORT *vp) {
	vp->TopLeftX = 0.0f;
	vp->TopLeftY = 0.0f;
	vp->Width = static_cast<float>(CLIENTWIDTH);
	vp->Height = static_cast<float>(CLIENTHEIGHT);
	vp->MinDepth = 0.0f;
	vp->MaxDepth = 0.0f;
}
void Render()
{
	// Just clear the backbuffer
	ppImmediateContext->ClearRenderTargetView(pRenderTargetView, (const FLOAT*)(&Colors::Black));
	ppSwapChain->Present(0, 0);
}

void CleanupDevice()
{
	if (ppImmediateContext) ppImmediateContext->ClearState();

	if (pRenderTargetView) pRenderTargetView->Release();
	if (ppSwapChain) ppSwapChain->Release();
	if (ppImmediateContext) ppImmediateContext->Release();
	if (ppDevice) ppDevice->Release();
}<|endoftext|>


<commit_before>#include <UtH/Engine/GameObject.hpp>
#include <UtH/Renderer/Camera.hpp>
#include <UtH/Renderer/RenderTarget.hpp>
#include <UtH/Platform/Debug.hpp>

using namespace uth;

GameObject::GameObject()
{

}

GameObject::GameObject(const std::string &tag)
	: Object(tag)
{
}

uth::GameObject::GameObject(const std::vector<std::string>& tags)
	: Object(tags)
{
}

GameObject::~GameObject()
{
	RemoveComponents();
}

void GameObject::RemoveComponent(Component* component)
{
    for (size_t i = 0; i < m_components.size(); ++i)
	{
        if (m_components.at(i).get() == component)
		{
            m_components.erase(m_components.begin() + i);
		}
	}
}

void GameObject::RemoveComponent(const std::string& name)
{
    for (size_t i = 0; i < m_components.size(); ++i)
	{
        if (m_components.at(i)->GetName() == name)
		{
            m_components.erase(m_components.begin() + i);
		}
	}
}

void GameObject::RemoveComponents()
{
    m_components.clear();
}

void GameObject::Draw(RenderTarget& target, RenderAttributes attributes)
{
	if (!m_active)
		return;

	target.Bind();

    Shader* tempShader = &target.GetShader();
    Camera* tempCamera = &target.GetCamera();

    Shader& shader = attributes.shader ? *attributes.shader : target.GetShader();
    Camera& camera = attributes.camera ? *attributes.camera : target.GetCamera();
    target.SetShader(&shader);
    target.SetCamera(&camera);

    shader.SetUniform("unifModel", transform.GetTransform());
    shader.SetUniform("unifProjection", target.GetCamera().GetProjectionTransform());

    draw(target);

	const std::vector<std::shared_ptr<Component>> objBackup(m_components);
	for (int i = 0; i < objBackup.size(); ++i)
	{
		target.GetShader().Use();
		if (objBackup[i]->IsActive())
			objBackup[i]->Draw(target);
	}

    target.SetShader(tempShader);
    target.SetCamera(tempCamera);
	Object::Draw(target);
}

void GameObject::Update(float dt)
{
	if(!m_active)
		return;

	update(dt);

	for (auto& i : m_components)
	{
		if (i->IsActive())
			i->Update(dt);
	}
	Object::Update(dt);
}<commit_msg>Fixed RenderAttributes for GameObject's children<commit_after>#include <UtH/Engine/GameObject.hpp>
#include <UtH/Renderer/Camera.hpp>
#include <UtH/Renderer/RenderTarget.hpp>
#include <UtH/Platform/Debug.hpp>

using namespace uth;

GameObject::GameObject()
{

}

GameObject::GameObject(const std::string &tag)
	: Object(tag)
{
}

uth::GameObject::GameObject(const std::vector<std::string>& tags)
	: Object(tags)
{
}

GameObject::~GameObject()
{
	RemoveComponents();
}

void GameObject::RemoveComponent(Component* component)
{
    for (size_t i = 0; i < m_components.size(); ++i)
	{
        if (m_components.at(i).get() == component)
		{
            m_components.erase(m_components.begin() + i);
		}
	}
}

void GameObject::RemoveComponent(const std::string& name)
{
    for (size_t i = 0; i < m_components.size(); ++i)
	{
        if (m_components.at(i)->GetName() == name)
		{
            m_components.erase(m_components.begin() + i);
		}
	}
}

void GameObject::RemoveComponents()
{
    m_components.clear();
}

void GameObject::Draw(RenderTarget& target, RenderAttributes attributes)
{
	if (!m_active)
		return;

	target.Bind();

    Shader* tempShader = &target.GetShader();
    Camera* tempCamera = &target.GetCamera();

    Shader& shader = attributes.shader ? *attributes.shader : target.GetShader();
    Camera& camera = attributes.camera ? *attributes.camera : target.GetCamera();
    target.SetShader(&shader);
    target.SetCamera(&camera);

    shader.SetUniform("unifModel", transform.GetTransform());
    shader.SetUniform("unifProjection", target.GetCamera().GetProjectionTransform());

    draw(target);

	const std::vector<std::shared_ptr<Component>> objBackup(m_components);
	for (int i = 0; i < objBackup.size(); ++i)
	{
		target.GetShader().Use();
		if (objBackup[i]->IsActive())
			objBackup[i]->Draw(target);
	}

    Object::Draw(target, attributes);

    target.SetShader(tempShader);
    target.SetCamera(tempCamera);
}

void GameObject::Update(float dt)
{
	if(!m_active)
		return;

	update(dt);

	for (auto& i : m_components)
	{
		if (i->IsActive())
			i->Update(dt);
	}
	Object::Update(dt);
}<|endoftext|>


<commit_before>// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "openMVG/exif_IO/exif_IO_EasyExif.hpp"

#include "openMVG_Samples/sensorWidthDatabase/ParseDatabase.hpp"

#include "openMVG/image/image.hpp"
#include "openMVG/split/split.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
#include <vector>

/// Check that Kmatrix is a string like "f;0;ppx;0;f;ppy;0;0;1"
/// With f,ppx,ppy as valid numerical value
bool checkIntrinsicStringValidity(const std::string & Kmatrix)
{
  std::vector<std::string> vec_str;
  split( Kmatrix, ";", vec_str );
  if (vec_str.size() != 9)  {
    std::cerr << "\n Missing ';' character" << std::endl;
    return false;
  }
  // Check that all K matrix value are valid numbers
  for (size_t i = 0; i < vec_str.size(); ++i) {
    double readvalue = 0.0;
    std::stringstream ss;
    ss.str(vec_str[i]);
    if (! (ss >> readvalue) )  {
      std::cerr << "\n Used an invalid not a number character" << std::endl;
      return false;
    }
  }
  return true;
}

int main(int argc, char **argv)
{
  CmdLine cmd;

  std::string sImageDir,
    sfileDatabase = "",
    sOutputDir = "",
    sKmatrix;

  double focalPixPermm = -1.0;

  cmd.add( make_option('i', sImageDir, "imageDirectory") );
  cmd.add( make_option('d', sfileDatabase, "sensorWidthDatabase") );
  cmd.add( make_option('o', sOutputDir, "outputDirectory") );
  cmd.add( make_option('f', focalPixPermm, "focal") );
  cmd.add( make_option('k', sKmatrix, "intrinsics") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--imageDirectory]\n"
      << "[-d|--sensorWidthDatabase]\n"
      << "[-o|--outputDirectory]\n"
      << "[-f|--focal] (pixels)\n"
      << "[-k|--intrinsics] Kmatrix: \"f;0;ppx;0;f;ppy;0;0;1\""
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  std::cout << " You called : " <<std::endl
            << argv[0] << std::endl
            << "--imageDirectory " << sImageDir << std::endl
            << "--sensorWidthDatabase " << sfileDatabase << std::endl
            << "--outputDirectory " << sOutputDir << std::endl
            << "--focal " << focalPixPermm << std::endl
            << "--intrinsics " << sKmatrix << std::endl;

  if ( !stlplus::folder_exists( sImageDir ) )
  {
    std::cerr << "\nThe input directory doesn't exist" << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutputDir.empty())
  {
    std::cerr << "\nInvalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if ( !stlplus::folder_exists( sOutputDir ) )
  {
    if ( !stlplus::folder_create( sOutputDir ))
    {
      std::cerr << "\nCannot create output directory" << std::endl;
      return EXIT_FAILURE;
    }
  }

  if (sKmatrix.size() > 0 && !checkIntrinsicStringValidity(sKmatrix) )
  {
    std::cerr << "\nInvalid K matrix input" << std::endl;
    return EXIT_FAILURE;
  }

  if (sKmatrix.size() > 0 && focalPixPermm != -1.0)
  {
    std::cerr << "\nCannot combine -f and -k options" << std::endl;
    return EXIT_FAILURE;
  }

  std::vector<std::string> vec_image = stlplus::folder_files( sImageDir );
  // Write the new file
  std::ofstream listTXT( stlplus::create_filespec( sOutputDir,
                                                   "lists.txt" ).c_str() );
  if ( listTXT )
  {
    std::sort(vec_image.begin(), vec_image.end());
    for ( std::vector<std::string>::const_iterator iter_image = vec_image.begin();
      iter_image != vec_image.end();
      iter_image++ )
    {
      // Read meta data to fill width height and focalPixPermm
      std::string sImageFilename = stlplus::create_filespec( sImageDir, *iter_image );

      // Test if the image format is supported:
      if (openMVG::GetFormat(sImageFilename.c_str()) == openMVG::Unknown)
        continue; // image cannot be opened

      size_t width = -1;
      size_t height = -1;

      std::auto_ptr<Exif_IO> exifReader (new Exif_IO_EasyExif() );
      exifReader->open( sImageFilename );

      // Consider the case where focal is provided

      std::ostringstream os;
      //If image do not contains meta data
      if ( !exifReader->doesHaveExifInfo() || focalPixPermm != -1)
      {
        Image<unsigned char> image;
        if (openMVG::ReadImage( sImageFilename.c_str(), &image))  {
          width = image.Width();
          height = image.Height();
        }
        else
        {
          Image<RGBColor> imageRGB;
          if (openMVG::ReadImage( sImageFilename.c_str(), &imageRGB)) {
            width = imageRGB.Width();
            height = imageRGB.Height();
          }
          else
          {
            Image<RGBAColor> imageRGBA;
            if (openMVG::ReadImage( sImageFilename.c_str(), &imageRGBA))  {
              width = imageRGBA.Width();
              height = imageRGBA.Height();
            }
            else
              continue; // image is not considered, cannot be read
          }
        }
        os << *iter_image << ";" << width << ";" << height;
        if ( focalPixPermm == -1 && sKmatrix.size() == 0)
          os << std::endl;
        else
        {
          if (sKmatrix.size() > 0) // Known intrinsic matrix
          {
            os << ";" << sKmatrix << std::endl;
          }
          else
            os << ";"
              << focalPixPermm << ";" << 0 << ";" << width/2.0 << ";"
              << 0 << ";" << focalPixPermm << ";" << height/2.0 << ";"
              << 0 << ";" << 0 << ";" << 1 << std::endl;
        }
      }
      else // If image contains meta data
      {
        double focal = focalPixPermm;
        width = exifReader->getWidth();
        height = exifReader->getHeight();
        const std::string sCamName = exifReader->getBrand();
        const std::string sCamModel = exifReader->getModel();

          std::vector<Datasheet> vec_database;
          Datasheet datasheet;
          if ( parseDatabase( sfileDatabase, vec_database ) )
          {
            if ( getInfo( sCamName, sCamModel, vec_database, datasheet ) )
            {
              // The camera model was found in the database so we can compute it's approximated focal length
              const double ccdw = datasheet._sensorSize;
              focal = std::max ( width, height ) * exifReader->getFocal() / ccdw;
              os << *iter_image << ";" << width << ";" << height << ";" << focal << ";" << sCamName << ";" << sCamModel << std::endl;
            }
            else
            {
              std::cout << "Camera \"" << sCamName << "\" model \"" << sCamModel << "\" doesn't exist in the database" << std::endl;
              os << *iter_image << ";" << width << ";" << height << ";" << sCamName << ";" << sCamModel << std::endl;
            }
          }
          else
          {
            std::cout << "Sensor width database \"" << sfileDatabase << "\" doesn't exist." << std::endl;
            std::cout << "Please consider add your camera model in the database." << std::endl;
            os << *iter_image << ";" << width << ";" << height << ";" << sCamName << ";" << sCamModel << std::endl;
          }
        }
      std::cout << os.str();
      listTXT << os.str();
    }
  }
  listTXT.close();
  return EXIT_SUCCESS;
}
<commit_msg>handle Exif::Width or Exif::Width that can be equal to 0. Enhance logging. #195<commit_after>// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "openMVG/exif_IO/exif_IO_EasyExif.hpp"

#include "openMVG_Samples/sensorWidthDatabase/ParseDatabase.hpp"

#include "openMVG/image/image.hpp"
#include "openMVG/split/split.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
#include <vector>

/// Check that Kmatrix is a string like "f;0;ppx;0;f;ppy;0;0;1"
/// With f,ppx,ppy as valid numerical value
bool checkIntrinsicStringValidity(const std::string & Kmatrix)
{
  std::vector<std::string> vec_str;
  split( Kmatrix, ";", vec_str );
  if (vec_str.size() != 9)  {
    std::cerr << "\n Missing ';' character" << std::endl;
    return false;
  }
  // Check that all K matrix value are valid numbers
  for (size_t i = 0; i < vec_str.size(); ++i) {
    double readvalue = 0.0;
    std::stringstream ss;
    ss.str(vec_str[i]);
    if (! (ss >> readvalue) )  {
      std::cerr << "\n Used an invalid not a number character" << std::endl;
      return false;
    }
  }
  return true;
}

int main(int argc, char **argv)
{
  CmdLine cmd;

  std::string sImageDir,
    sfileDatabase = "",
    sOutputDir = "",
    sKmatrix;

  double focalPixPermm = -1.0;

  cmd.add( make_option('i', sImageDir, "imageDirectory") );
  cmd.add( make_option('d', sfileDatabase, "sensorWidthDatabase") );
  cmd.add( make_option('o', sOutputDir, "outputDirectory") );
  cmd.add( make_option('f', focalPixPermm, "focal") );
  cmd.add( make_option('k', sKmatrix, "intrinsics") );

  try {
      if (argc == 1) throw std::string("Invalid command line parameter.");
      cmd.process(argc, argv);
  } catch(const std::string& s) {
      std::cerr << "Usage: " << argv[0] << '\n'
      << "[-i|--imageDirectory]\n"
      << "[-d|--sensorWidthDatabase]\n"
      << "[-o|--outputDirectory]\n"
      << "[-f|--focal] (pixels)\n"
      << "[-k|--intrinsics] Kmatrix: \"f;0;ppx;0;f;ppy;0;0;1\""
      << std::endl;

      std::cerr << s << std::endl;
      return EXIT_FAILURE;
  }

  std::cout << " You called : " <<std::endl
            << argv[0] << std::endl
            << "--imageDirectory " << sImageDir << std::endl
            << "--sensorWidthDatabase " << sfileDatabase << std::endl
            << "--outputDirectory " << sOutputDir << std::endl
            << "--focal " << focalPixPermm << std::endl
            << "--intrinsics " << sKmatrix << std::endl;

  if ( !stlplus::folder_exists( sImageDir ) )
  {
    std::cerr << "\nThe input directory doesn't exist" << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutputDir.empty())
  {
    std::cerr << "\nInvalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if ( !stlplus::folder_exists( sOutputDir ) )
  {
    if ( !stlplus::folder_create( sOutputDir ))
    {
      std::cerr << "\nCannot create output directory" << std::endl;
      return EXIT_FAILURE;
    }
  }

  if (sKmatrix.size() > 0 && !checkIntrinsicStringValidity(sKmatrix) )
  {
    std::cerr << "\nInvalid K matrix input" << std::endl;
    return EXIT_FAILURE;
  }

  if (sKmatrix.size() > 0 && focalPixPermm != -1.0)
  {
    std::cerr << "\nCannot combine -f and -k options" << std::endl;
    return EXIT_FAILURE;
  }

  std::vector<Datasheet> vec_database;
  if (!sfileDatabase.empty())
  {
    if ( !parseDatabase( sfileDatabase, vec_database ) )
    {
      std::cerr << "\nInvalid input database" << std::endl;
      return EXIT_FAILURE;
    }
  }

  std::vector<std::string> vec_image = stlplus::folder_files( sImageDir );
  // Write the new file
  std::ofstream listTXT( stlplus::create_filespec( sOutputDir,
                                                   "lists.txt" ).c_str() );
  if ( listTXT )
  {
    std::sort(vec_image.begin(), vec_image.end());
    for ( std::vector<std::string>::const_iterator iter_image = vec_image.begin();
      iter_image != vec_image.end();
      iter_image++ )
    {
      // Read meta data to fill width height and focalPixPermm
      const std::string sImageFilename = stlplus::create_filespec( sImageDir, *iter_image );

      // Test if the image format is supported:
      if (openMVG::GetFormat(sImageFilename.c_str()) == openMVG::Unknown)
        continue; // image cannot be opened

      size_t width = -1;
      size_t height = -1;

      std::auto_ptr<Exif_IO> exifReader (new Exif_IO_EasyExif() );
      exifReader->open( sImageFilename );

      // Consider the case where focal is provided

      std::ostringstream os;
      //If image do not contains meta data
      if ( !exifReader->doesHaveExifInfo() || focalPixPermm != -1)
      {
        Image<unsigned char> image;
        if (openMVG::ReadImage( sImageFilename.c_str(), &image))  {
          width = image.Width();
          height = image.Height();
        } // Since read image perform an explicit image conversion
          //(we do not have to test RGB/A formats)
        else
          continue; // image is not considered, cannot be read

        os << *iter_image << ";" << width << ";" << height;
        if ( focalPixPermm == -1 && sKmatrix.size() == 0)
          os << std::endl;
        else
        {
          if (sKmatrix.size() > 0) // Known intrinsic matrix
          {
            os << ";" << sKmatrix << std::endl;
          }
          else
            os << ";"
              << focalPixPermm << ";" << 0 << ";" << width/2.0 << ";"
              << 0 << ";" << focalPixPermm << ";" << height/2.0 << ";"
              << 0 << ";" << 0 << ";" << 1 << std::endl;
        }
      }
      else // If image contains meta data
      {
        const std::string sCamName = exifReader->getBrand();
        const std::string sCamModel = exifReader->getModel();

        width = exifReader->getWidth();
        height = exifReader->getHeight();

        // Handle case where EXIF height or width is not present
        if (width == 0 || height == 0)
        {
          Image<unsigned char> image;
          if (openMVG::ReadImage( sImageFilename.c_str(), &image))  {
            width = image.Width();
            height = image.Height();
          }
          else
            continue;  // image is not considered, cannot be read
        }
        // Handle case where focal length is equal to 0
        if (exifReader->getFocal() == 0.0f)
        {
          std::cerr << stlplus::basename_part(sImageFilename) << ": Focal length is missing." << std::endl;
          continue;
        }

        // Create the image entry in the list file
        {
          Datasheet datasheet;
          if ( getInfo( sCamName, sCamModel, vec_database, datasheet ))
          {
            // The camera model was found in the database so we can compute it's approximated focal length
            const double ccdw = datasheet._sensorSize;
            const double focal = std::max ( width, height ) * exifReader->getFocal() / ccdw;
            os << *iter_image << ";" << width << ";" << height << ";" << focal << ";" << sCamName << ";" << sCamModel << std::endl;
          }
          else
          {
            std::cout << stlplus::basename_part(sImageFilename) << ": Camera \""
              << sCamName << "\" model \"" << sCamModel << "\" doesn't exist in the database" << std::endl
              << "Please consider add your camera model and sensor width in the database." << std::endl;
            os << *iter_image << ";" << width << ";" << height << ";" << sCamName << ";" << sCamModel << std::endl;
          }
        }
      }
      std::cout << os.str();
      listTXT << os.str();
    }
  }
  listTXT.close();
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

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

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "nonlinear_implicit_system.h"
#include "petsc_nonlinear_solver.h"
#include "petsc_linear_solver.h"
#include "petsc_vector.h"
#include "petsc_matrix.h"
#include "system.h"
#include "dof_map.h"
#include "preconditioner.h"

namespace libMesh
{

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

  //-------------------------------------------------------------------
  // this function is called by PETSc at the end of each nonlinear step
  PetscErrorCode
  __libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
  {
    //int ierr=0;

    //if (its > 0)
      libMesh::out << "  NL step "
		    << std::setw(2) << its
		    << std::scientific
		    << ", |residual|_2 = " << fnorm
		    << std::endl;

    //return ierr;
    return 0;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the residual at X
  PetscErrorCode
  __libmesh_petsc_snes_residual (SNES, Vec x, Vec r, void *ctx)
  {
    int ierr=0;

    libmesh_assert (x   != NULL);
    libmesh_assert (r   != NULL);
    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscVector<Number>& R_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);
    PetscVector<Number> X_global(x), R(r);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    R.swap(R_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);

    sys.update();

    //Swap back
    X_global.swap(X_sys);
    R.swap(R_sys);

    R.zero();

    if      (solver->residual != NULL) solver->residual (*sys.current_local_solution.get(), R, sys);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), &R, NULL, sys);
    else libmesh_error();

    R.close();
    X_global.close();

    return ierr;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the Jacobian at X
  PetscErrorCode
  __libmesh_petsc_snes_jacobian (SNES, Vec x, Mat *jac, Mat *pc, MatStructure *msflag, void *ctx)
  {
    int ierr=0;

    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscMatrix<Number> PC(*pc);
    PetscMatrix<Number> Jac(*jac);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscMatrix<Number>& Jac_sys = *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);
    PetscVector<Number> X_global(x);

    // Set the dof maps
    PC.attach_dof_map(sys.get_dof_map());
    Jac.attach_dof_map(sys.get_dof_map());

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);
    sys.update();

    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    PC.zero();

    if      (solver->jacobian != NULL) solver->jacobian (*sys.current_local_solution.get(), PC, sys);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), NULL, &PC, sys);
    else libmesh_error();

    PC.close();
    Jac.close();
    X_global.close();

    *msflag = SAME_NONZERO_PATTERN;

    return ierr;
  }

} // end extern "C"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// PetscNonlinearSolver<> methods
template <typename T>
void PetscNonlinearSolver<T>::clear ()
{
  if (this->initialized())
    {
      this->_is_initialized = false;

      int ierr=0;

      ierr = SNESDestroy(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
void PetscNonlinearSolver<T>::init ()
{
  // Initialize the data structures if not done so already.
  if (!this->initialized())
    {
      this->_is_initialized = true;

      int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
      // At least until Petsc 2.1.1, the SNESCreate had a different calling syntax.
      // The second argument was of type SNESProblemType, and could have a value of
      // either SNES_NONLINEAR_EQUATIONS or SNES_UNCONSTRAINED_MINIMIZATION.
      ierr = SNESCreate(libMesh::COMM_WORLD, SNES_NONLINEAR_EQUATIONS, &_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#else

      ierr = SNESCreate(libMesh::COMM_WORLD,&_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
      ierr = SNESSetMonitor (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#else
      // API name change in PETSc 2.3.3
      ierr = SNESMonitorSet (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#endif
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      ierr = SNESSetFromOptions(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      if(this->_preconditioner)
      {
        KSP ksp;
        ierr = SNESGetKSP (_snes, &ksp);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);
        PC pc;
        ierr = KSPGetPC(ksp,&pc);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);

        PCSetType(pc, PCSHELL);
        PCShellSetContext(pc,(void*)this->_preconditioner);

        //Re-Use the shell functions from petsc_linear_solver
        PCShellSetSetUp(pc,__libmesh_petsc_preconditioner_setup);
        PCShellSetApply(pc,__libmesh_petsc_preconditioner_apply);
      }
    }
}

template <typename T>
std::pair<unsigned int, Real>
PetscNonlinearSolver<T>::solve (SparseMatrix<T>&  jac_in,  // System Jacobian Matrix
				NumericVector<T>& x_in,    // Solution vector
				NumericVector<T>& r_in,    // Residual vector
				const double,              // Stopping tolerance
				const unsigned int)
{
  this->init ();

  // Make sure the data passed in are really of Petsc types
  PetscMatrix<T>* jac = libmesh_cast_ptr<PetscMatrix<T>*>(&jac_in);
  PetscVector<T>* x   = libmesh_cast_ptr<PetscVector<T>*>(&x_in);
  PetscVector<T>* r   = libmesh_cast_ptr<PetscVector<T>*>(&r_in);

  int ierr=0;
  int n_iterations =0;
  // Should actually be a PetscReal, but I don't know which version of PETSc first introduced PetscReal
  Real final_residual_norm=0.;

  ierr = SNESSetFunction (_snes, r->vec(), __libmesh_petsc_snes_residual, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESSetJacobian (_snes, jac->mat(), jac->mat(), __libmesh_petsc_snes_jacobian, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

   // Have the Krylov subspace method use our good initial guess rather than 0
   KSP ksp;
   ierr = SNESGetKSP (_snes, &ksp);
          CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the iterative solver.  Use the user-supplied
  // tolerance for the relative residual & leave the others at default values
  ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
                           PETSC_DEFAULT, this->max_linear_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the non-linear solver.
  ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance,
                           this->absolute_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  //Pull in command-line options
  KSPSetFromOptions(ksp);
  SNESSetFromOptions(_snes);

  //Set the preconditioning matrix
  if(this->_preconditioner)
    this->_preconditioner->set_matrix(jac_in);

//    ierr = KSPSetInitialGuessNonzero (ksp, PETSC_TRUE);
//           CHKERRABORT(libMesh::COMM_WORLD,ierr);

// Older versions (at least up to 2.1.5) of SNESSolve took 3 arguments,
// the last one being a pointer to an int to hold the number of iterations required.
# if PETSC_VERSION_LESS_THAN(2,2,0)

 ierr = SNESSolve (_snes, x->vec(), &n_iterations);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

 ierr = SNESSolve (_snes, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.3.x & newer style
#else

  ierr = SNESSolve (_snes, PETSC_NULL, x->vec());
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESGetIterationNumber(_snes,&n_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESGetFunctionNorm(_snes,&final_residual_norm);
	 CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes,&reason);

  //Based on Petsc 2.3.3 documentation all diverged reasons are negative
  this->converged = reason >= 0;

  this->clear();

  // return the # of its. and the final residual norm.
  return std::make_pair(n_iterations, final_residual_norm);
}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscNonlinearSolver<Number>;

} // namespace libMesh

#endif // #ifdef LIBMESH_HAVE_PETSC
<commit_msg>Added PerfLog lines for PetscNonlinearSolver<commit_after>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

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

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh_common.h"

#ifdef LIBMESH_HAVE_PETSC

// C++ includes

// Local Includes
#include "nonlinear_implicit_system.h"
#include "petsc_nonlinear_solver.h"
#include "petsc_linear_solver.h"
#include "petsc_vector.h"
#include "petsc_matrix.h"
#include "system.h"
#include "dof_map.h"
#include "preconditioner.h"

namespace libMesh
{

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

  //-------------------------------------------------------------------
  // this function is called by PETSc at the end of each nonlinear step
  PetscErrorCode
  __libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
  {
    //int ierr=0;

    //if (its > 0)
      libMesh::out << "  NL step "
		    << std::setw(2) << its
		    << std::scientific
		    << ", |residual|_2 = " << fnorm
		    << std::endl;

    //return ierr;
    return 0;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the residual at X
  PetscErrorCode
  __libmesh_petsc_snes_residual (SNES, Vec x, Vec r, void *ctx)
  {
    START_LOG("residual()", "PetscNonlinearSolver");
    int ierr=0;

    libmesh_assert (x   != NULL);
    libmesh_assert (r   != NULL);
    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscVector<Number>& R_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);
    PetscVector<Number> X_global(x), R(r);

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    R.swap(R_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);

    sys.update();

    //Swap back
    X_global.swap(X_sys);
    R.swap(R_sys);

    R.zero();

    if      (solver->residual != NULL) solver->residual (*sys.current_local_solution.get(), R, sys);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), &R, NULL, sys);
    else libmesh_error();

    R.close();
    X_global.close();

    STOP_LOG("residual()", "PetscNonlinearSolver");

    return ierr;
  }

  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the Jacobian at X
  PetscErrorCode
  __libmesh_petsc_snes_jacobian (SNES, Vec x, Mat *jac, Mat *pc, MatStructure *msflag, void *ctx)
  {
    START_LOG("jacobian()", "PetscNonlinearSolver");
    int ierr=0;

    libmesh_assert (ctx != NULL);

    PetscNonlinearSolver<Number>* solver =
      static_cast<PetscNonlinearSolver<Number>*> (ctx);

    NonlinearImplicitSystem &sys = solver->system();

    PetscMatrix<Number> PC(*pc);
    PetscMatrix<Number> Jac(*jac);
    PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
    PetscMatrix<Number>& Jac_sys = *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);
    PetscVector<Number> X_global(x);

    // Set the dof maps
    PC.attach_dof_map(sys.get_dof_map());
    Jac.attach_dof_map(sys.get_dof_map());

    // Use the systems update() to get a good local version of the parallel solution
    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    sys.get_dof_map().enforce_constraints_exactly(sys);
    sys.update();

    X_global.swap(X_sys);
    Jac.swap(Jac_sys);

    PC.zero();

    if      (solver->jacobian != NULL) solver->jacobian (*sys.current_local_solution.get(), PC, sys);
    else if (solver->matvec   != NULL) solver->matvec   (*sys.current_local_solution.get(), NULL, &PC, sys);
    else libmesh_error();

    PC.close();
    Jac.close();
    X_global.close();

    *msflag = SAME_NONZERO_PATTERN;

    STOP_LOG("jacobian()", "PetscNonlinearSolver");

    return ierr;
  }

} // end extern "C"
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// PetscNonlinearSolver<> methods
template <typename T>
void PetscNonlinearSolver<T>::clear ()
{
  if (this->initialized())
    {
      this->_is_initialized = false;

      int ierr=0;

      ierr = SNESDestroy(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);
    }
}

template <typename T>
void PetscNonlinearSolver<T>::init ()
{
  // Initialize the data structures if not done so already.
  if (!this->initialized())
    {
      this->_is_initialized = true;

      int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
      // At least until Petsc 2.1.1, the SNESCreate had a different calling syntax.
      // The second argument was of type SNESProblemType, and could have a value of
      // either SNES_NONLINEAR_EQUATIONS or SNES_UNCONSTRAINED_MINIMIZATION.
      ierr = SNESCreate(libMesh::COMM_WORLD, SNES_NONLINEAR_EQUATIONS, &_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#else

      ierr = SNESCreate(libMesh::COMM_WORLD,&_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
      ierr = SNESSetMonitor (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#else
      // API name change in PETSc 2.3.3
      ierr = SNESMonitorSet (_snes, __libmesh_petsc_snes_monitor,
			     this, PETSC_NULL);
#endif
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      ierr = SNESSetFromOptions(_snes);
             CHKERRABORT(libMesh::COMM_WORLD,ierr);

      if(this->_preconditioner)
      {
        KSP ksp;
        ierr = SNESGetKSP (_snes, &ksp);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);
        PC pc;
        ierr = KSPGetPC(ksp,&pc);
               CHKERRABORT(libMesh::COMM_WORLD,ierr);

        PCSetType(pc, PCSHELL);
        PCShellSetContext(pc,(void*)this->_preconditioner);

        //Re-Use the shell functions from petsc_linear_solver
        PCShellSetSetUp(pc,__libmesh_petsc_preconditioner_setup);
        PCShellSetApply(pc,__libmesh_petsc_preconditioner_apply);
      }
    }
}

template <typename T>
std::pair<unsigned int, Real>
PetscNonlinearSolver<T>::solve (SparseMatrix<T>&  jac_in,  // System Jacobian Matrix
				NumericVector<T>& x_in,    // Solution vector
				NumericVector<T>& r_in,    // Residual vector
				const double,              // Stopping tolerance
				const unsigned int)
{
  START_LOG("solve()", "PetscNonlinearSolver");
  this->init ();

  // Make sure the data passed in are really of Petsc types
  PetscMatrix<T>* jac = libmesh_cast_ptr<PetscMatrix<T>*>(&jac_in);
  PetscVector<T>* x   = libmesh_cast_ptr<PetscVector<T>*>(&x_in);
  PetscVector<T>* r   = libmesh_cast_ptr<PetscVector<T>*>(&r_in);

  int ierr=0;
  int n_iterations =0;
  // Should actually be a PetscReal, but I don't know which version of PETSc first introduced PetscReal
  Real final_residual_norm=0.;

  ierr = SNESSetFunction (_snes, r->vec(), __libmesh_petsc_snes_residual, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESSetJacobian (_snes, jac->mat(), jac->mat(), __libmesh_petsc_snes_jacobian, this);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

   // Have the Krylov subspace method use our good initial guess rather than 0
   KSP ksp;
   ierr = SNESGetKSP (_snes, &ksp);
          CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the iterative solver.  Use the user-supplied
  // tolerance for the relative residual & leave the others at default values
  ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
                           PETSC_DEFAULT, this->max_linear_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Set the tolerances for the non-linear solver.
  ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance,
                           this->absolute_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  //Pull in command-line options
  KSPSetFromOptions(ksp);
  SNESSetFromOptions(_snes);

  //Set the preconditioning matrix
  if(this->_preconditioner)
    this->_preconditioner->set_matrix(jac_in);

//    ierr = KSPSetInitialGuessNonzero (ksp, PETSC_TRUE);
//           CHKERRABORT(libMesh::COMM_WORLD,ierr);

// Older versions (at least up to 2.1.5) of SNESSolve took 3 arguments,
// the last one being a pointer to an int to hold the number of iterations required.
# if PETSC_VERSION_LESS_THAN(2,2,0)

 ierr = SNESSolve (_snes, x->vec(), &n_iterations);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

 ierr = SNESSolve (_snes, x->vec());
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

// 2.3.x & newer style
#else

  ierr = SNESSolve (_snes, PETSC_NULL, x->vec());
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESGetIterationNumber(_snes,&n_iterations);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = SNESGetFunctionNorm(_snes,&final_residual_norm);
	 CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes,&reason);

  //Based on Petsc 2.3.3 documentation all diverged reasons are negative
  this->converged = reason >= 0;

  this->clear();

  STOP_LOG("solve()", "PetscNonlinearSolver");

  // return the # of its. and the final residual norm.
  return std::make_pair(n_iterations, final_residual_norm);
}

//------------------------------------------------------------------
// Explicit instantiations
template class PetscNonlinearSolver<Number>;

} // namespace libMesh

#endif // #ifdef LIBMESH_HAVE_PETSC
<|endoftext|>