<commit_before>/*
    Copyright (C) 2011 Collabora Ltd. <info@collabora.co.uk>
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

    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 program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "applicationsource.h"
#include "../elementfactory.h"
#include <gst/app/gstappsrc.h>

namespace QGst {
namespace Utils {

#ifndef DOXYGEN_RUN

struct QTGSTREAMERUTILS_NO_EXPORT ApplicationSource::Priv
{
public:
    ElementPtr m_appsrc;

    void lazyConstruct(ApplicationSource *self);
    void setCallbacks(ApplicationSource *self);

    inline GstAppSrc *appSrc()
    {
        return reinterpret_cast<GstAppSrc*>(static_cast<GstElement*>(m_appsrc));
    }

private:
    static void need_data(GstAppSrc *src, guint length, gpointer user_data);
    static void enough_data(GstAppSrc *src, gpointer user_data);
    static gboolean seek_data(GstAppSrc *src, guint64 offset, gpointer user_data);

    static void need_data_noop(GstAppSrc*, guint, gpointer) {}
    static void enough_data_noop(GstAppSrc*, gpointer) {}
    static gboolean seek_data_noop(GstAppSrc*, guint64, gpointer) { return FALSE; }
};

void ApplicationSource::Priv::lazyConstruct(ApplicationSource *self)
{
    if (!m_appsrc) {
        m_appsrc = QGst::ElementFactory::make("appsrc");
        if (!m_appsrc) {
            qWarning() << "Failed to construct appsrc";
        }
        setCallbacks(self);
    }
}

void ApplicationSource::Priv::setCallbacks(ApplicationSource *self)
{
    if (m_appsrc) {
        if (self) {
            static GstAppSrcCallbacks callbacks = { &need_data, &enough_data, &seek_data };
            gst_app_src_set_callbacks(appSrc(), &callbacks, self, NULL);
        } else {
            static GstAppSrcCallbacks callbacks = { &need_data_noop, &enough_data_noop, &seek_data_noop };
            gst_app_src_set_callbacks(appSrc(), &callbacks, NULL, NULL);
        }
    }
}

void ApplicationSource::Priv::need_data(GstAppSrc *src, guint length, gpointer user_data)
{
    Q_UNUSED(src);
    static_cast<ApplicationSource*>(user_data)->needData(length);
}

void ApplicationSource::Priv::enough_data(GstAppSrc *src, gpointer user_data)
{
    Q_UNUSED(src);
    static_cast<ApplicationSource*>(user_data)->enoughData();
}

gboolean ApplicationSource::Priv::seek_data(GstAppSrc *src, guint64 offset, gpointer user_data)
{
    Q_UNUSED(src);
    return static_cast<ApplicationSource*>(user_data)->seekData(offset) ? TRUE : FALSE;
}

#endif //DOXYGEN_RUN

ApplicationSource::ApplicationSource()
    : d(new Priv)
{
}

ApplicationSource::~ApplicationSource()
{
    d->setCallbacks(NULL); //remove the callbacks from the source
    delete d;
}

ElementPtr ApplicationSource::element() const
{
    d->lazyConstruct(const_cast<ApplicationSource*>(this));
    return d->m_appsrc;
}

void ApplicationSource::setElement(const ElementPtr & appsrc)
{
    Q_ASSERT(QGlib::Type::fromInstance(appsrc).isA(GST_TYPE_APP_SRC));
    d->setCallbacks(NULL); //remove the callbacks from the previous source
    d->m_appsrc = appsrc;
    d->setCallbacks(this);
}

CapsPtr ApplicationSource::caps() const
{
    CapsPtr c;
    if (d->appSrc()) {
        c = CapsPtr::wrap(gst_app_src_get_caps(d->appSrc()), false);
    }
    return c;
}

void ApplicationSource::setCaps(const CapsPtr & caps)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_caps(d->appSrc(), caps);
    }
}

quint64 ApplicationSource::minLatency() const
{
    guint64 ret = -1;
    if (d->appSrc()) {
        gst_app_src_get_latency(d->appSrc(), &ret, NULL);
    }
    return ret;
}

quint64 ApplicationSource::maxLatency() const
{
    guint64 ret = -1;
    if (d->appSrc()) {
        gst_app_src_get_latency(d->appSrc(), NULL, &ret);
    }
    return ret;
}

void ApplicationSource::setLatency(quint64 min, quint64 max)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_latency(d->appSrc(), min, max);
    }
}

qint64 ApplicationSource::size() const
{
    return d->appSrc() ? gst_app_src_get_size(d->appSrc()) : -1;
}

void ApplicationSource::setSize(qint64 size)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_size(d->appSrc(), size);
    }
}

AppStreamType ApplicationSource::streamType() const
{
    return d->appSrc() ? static_cast<AppStreamType>(gst_app_src_get_stream_type(d->appSrc()))
                       : AppStreamTypeStream;
}

void ApplicationSource::setStreamType(AppStreamType type)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_stream_type(d->appSrc(), static_cast<GstAppStreamType>(type));
    }
}

quint64 ApplicationSource::maxBytes() const
{
    return d->appSrc() ? gst_app_src_get_max_bytes(d->appSrc()) : 0;
}

void ApplicationSource::setMaxBytes(quint64 max)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_max_bytes(d->appSrc(), max);
    }
}

bool ApplicationSource::blockEnabled() const
{
    return d->m_appsrc ? d->m_appsrc->property("block").toBool() : false;
}

void ApplicationSource::enableBlock(bool enable)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("block", enable);
    }
}

bool ApplicationSource::isLive() const
{
    return d->m_appsrc ? d->m_appsrc->property("is-live").toBool() : false;
}

void ApplicationSource::setLive(bool islive)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("is-live", islive);
    }
}

uint ApplicationSource::minPercent() const
{
    return d->m_appsrc ? d->m_appsrc->property("min-percent").toUInt() : 0;
}

void ApplicationSource::setMinPercent(uint min)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("min-percent", min);
    }
}

Format ApplicationSource::format() const
{
    return d->m_appsrc ? d->m_appsrc->property("format").get<Format>() : FormatBytes;
}

void ApplicationSource::setFormat(Format f)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("format", f);
    }
}

FlowReturn ApplicationSource::pushBuffer(const BufferPtr & buffer)
{
    if (d->appSrc()) {
        return static_cast<FlowReturn>(gst_app_src_push_buffer(d->appSrc(), gst_buffer_ref(buffer)));
    } else {
        return FlowWrongState;
    }
}

FlowReturn ApplicationSource::endOfStream()
{
    if (d->appSrc()) {
        return static_cast<FlowReturn>(gst_app_src_end_of_stream(d->appSrc()));
    } else {
        return FlowWrongState;
    }
}

void ApplicationSource::needData(uint length)
{
    Q_UNUSED(length);
}

void ApplicationSource::enoughData()
{
}

bool ApplicationSource::seekData(quint64 offset)
{
    Q_UNUSED(offset);
    return false;
}

} //namespace Utils
} //namespace QGst
<commit_msg>src/QGst/Utils/applicationsource.cpp an additional callback was added to GstAppSrcCallbacks<commit_after>/*
    Copyright (C) 2011 Collabora Ltd. <info@collabora.co.uk>
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

    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 program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "applicationsource.h"
#include "../elementfactory.h"
#include <gst/app/gstappsrc.h>

namespace QGst {
namespace Utils {

#ifndef DOXYGEN_RUN

struct QTGSTREAMERUTILS_NO_EXPORT ApplicationSource::Priv
{
public:
    ElementPtr m_appsrc;

    void lazyConstruct(ApplicationSource *self);
    void setCallbacks(ApplicationSource *self);

    inline GstAppSrc *appSrc()
    {
        return reinterpret_cast<GstAppSrc*>(static_cast<GstElement*>(m_appsrc));
    }

private:
    static void need_data(GstAppSrc *src, guint length, gpointer user_data);
    static void enough_data(GstAppSrc *src, gpointer user_data);
    static gboolean seek_data(GstAppSrc *src, guint64 offset, gpointer user_data);

    static void need_data_noop(GstAppSrc*, guint, gpointer) {}
    static void enough_data_noop(GstAppSrc*, gpointer) {}
    static gboolean seek_data_noop(GstAppSrc*, guint64, gpointer) { return FALSE; }
};

void ApplicationSource::Priv::lazyConstruct(ApplicationSource *self)
{
    if (!m_appsrc) {
        m_appsrc = QGst::ElementFactory::make("appsrc");
        if (!m_appsrc) {
            qWarning() << "Failed to construct appsrc";
        }
        setCallbacks(self);
    }
}

void ApplicationSource::Priv::setCallbacks(ApplicationSource *self)
{
    if (m_appsrc) {
        if (self) {
            static GstAppSrcCallbacks callbacks = { &need_data, &enough_data, &seek_data, NULL };
            gst_app_src_set_callbacks(appSrc(), &callbacks, self, NULL);
        } else {
            static GstAppSrcCallbacks callbacks = { &need_data_noop, &enough_data_noop, &seek_data_noop, NULL };
            gst_app_src_set_callbacks(appSrc(), &callbacks, NULL, NULL);
        }
    }
}

void ApplicationSource::Priv::need_data(GstAppSrc *src, guint length, gpointer user_data)
{
    Q_UNUSED(src);
    static_cast<ApplicationSource*>(user_data)->needData(length);
}

void ApplicationSource::Priv::enough_data(GstAppSrc *src, gpointer user_data)
{
    Q_UNUSED(src);
    static_cast<ApplicationSource*>(user_data)->enoughData();
}

gboolean ApplicationSource::Priv::seek_data(GstAppSrc *src, guint64 offset, gpointer user_data)
{
    Q_UNUSED(src);
    return static_cast<ApplicationSource*>(user_data)->seekData(offset) ? TRUE : FALSE;
}

#endif //DOXYGEN_RUN

ApplicationSource::ApplicationSource()
    : d(new Priv)
{
}

ApplicationSource::~ApplicationSource()
{
    d->setCallbacks(NULL); //remove the callbacks from the source
    delete d;
}

ElementPtr ApplicationSource::element() const
{
    d->lazyConstruct(const_cast<ApplicationSource*>(this));
    return d->m_appsrc;
}

void ApplicationSource::setElement(const ElementPtr & appsrc)
{
    Q_ASSERT(QGlib::Type::fromInstance(appsrc).isA(GST_TYPE_APP_SRC));
    d->setCallbacks(NULL); //remove the callbacks from the previous source
    d->m_appsrc = appsrc;
    d->setCallbacks(this);
}

CapsPtr ApplicationSource::caps() const
{
    CapsPtr c;
    if (d->appSrc()) {
        c = CapsPtr::wrap(gst_app_src_get_caps(d->appSrc()), false);
    }
    return c;
}

void ApplicationSource::setCaps(const CapsPtr & caps)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_caps(d->appSrc(), caps);
    }
}

quint64 ApplicationSource::minLatency() const
{
    guint64 ret = -1;
    if (d->appSrc()) {
        gst_app_src_get_latency(d->appSrc(), &ret, NULL);
    }
    return ret;
}

quint64 ApplicationSource::maxLatency() const
{
    guint64 ret = -1;
    if (d->appSrc()) {
        gst_app_src_get_latency(d->appSrc(), NULL, &ret);
    }
    return ret;
}

void ApplicationSource::setLatency(quint64 min, quint64 max)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_latency(d->appSrc(), min, max);
    }
}

qint64 ApplicationSource::size() const
{
    return d->appSrc() ? gst_app_src_get_size(d->appSrc()) : -1;
}

void ApplicationSource::setSize(qint64 size)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_size(d->appSrc(), size);
    }
}

AppStreamType ApplicationSource::streamType() const
{
    return d->appSrc() ? static_cast<AppStreamType>(gst_app_src_get_stream_type(d->appSrc()))
                       : AppStreamTypeStream;
}

void ApplicationSource::setStreamType(AppStreamType type)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_stream_type(d->appSrc(), static_cast<GstAppStreamType>(type));
    }
}

quint64 ApplicationSource::maxBytes() const
{
    return d->appSrc() ? gst_app_src_get_max_bytes(d->appSrc()) : 0;
}

void ApplicationSource::setMaxBytes(quint64 max)
{
    d->lazyConstruct(this);
    if (d->appSrc()) {
        gst_app_src_set_max_bytes(d->appSrc(), max);
    }
}

bool ApplicationSource::blockEnabled() const
{
    return d->m_appsrc ? d->m_appsrc->property("block").toBool() : false;
}

void ApplicationSource::enableBlock(bool enable)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("block", enable);
    }
}

bool ApplicationSource::isLive() const
{
    return d->m_appsrc ? d->m_appsrc->property("is-live").toBool() : false;
}

void ApplicationSource::setLive(bool islive)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("is-live", islive);
    }
}

uint ApplicationSource::minPercent() const
{
    return d->m_appsrc ? d->m_appsrc->property("min-percent").toUInt() : 0;
}

void ApplicationSource::setMinPercent(uint min)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("min-percent", min);
    }
}

Format ApplicationSource::format() const
{
    return d->m_appsrc ? d->m_appsrc->property("format").get<Format>() : FormatBytes;
}

void ApplicationSource::setFormat(Format f)
{
    d->lazyConstruct(this);
    if (d->m_appsrc) {
        d->m_appsrc->setProperty("format", f);
    }
}

FlowReturn ApplicationSource::pushBuffer(const BufferPtr & buffer)
{
    if (d->appSrc()) {
        return static_cast<FlowReturn>(gst_app_src_push_buffer(d->appSrc(), gst_buffer_ref(buffer)));
    } else {
        return FlowWrongState;
    }
}

FlowReturn ApplicationSource::endOfStream()
{
    if (d->appSrc()) {
        return static_cast<FlowReturn>(gst_app_src_end_of_stream(d->appSrc()));
    } else {
        return FlowWrongState;
    }
}

void ApplicationSource::needData(uint length)
{
    Q_UNUSED(length);
}

void ApplicationSource::enoughData()
{
}

bool ApplicationSource::seekData(quint64 offset)
{
    Q_UNUSED(offset);
    return false;
}

} //namespace Utils
} //namespace QGst
<|endoftext|>


<commit_before>#pragma once

#include <limits>
#include <cassert>
#include <cmath>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"
#include "acmacs-base/range.hh"

// ----------------------------------------------------------------------

namespace acmacs
{
    class Coordinates : public Vector
    {
      public:
        using Vector::Vector;

        Coordinates(Location2D loc) : Vector{loc.x(), loc.y()} {}
        Coordinates(Location3D loc) : Vector{loc.x(), loc.y(), loc.z()} {}

        Coordinates transform(const Transformation& aTransformation) const
        {
            return aTransformation.transform(static_cast<Location2D>(*this));
        }

        bool not_nan() const
        {
            return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return !std::isnan(value); });
        }

        operator Location2D() const
        {
            assert(size() == 2);
            return {operator[](0), operator[](1)};
        }

        operator Location3D() const
        {
            assert(size() == 3);
            return {operator[](0), operator[](1), operator[](2)};
        }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

    // ----------------------------------------------------------------------

    struct Area
    {
        Coordinates min, max;

        Area(const Coordinates& a_min, const Coordinates& a_max) : min(a_min), max(a_max) {}
        Area(const Coordinates& a_min) : min(a_min), max(a_min) {}

        size_t num_dim() const { return min.size(); }

        void extend(const Coordinates& point)
        {
            for (size_t dim = 0; dim < num_dim(); ++dim) {
                if (point[dim] < min[dim])
                    min[dim] = point[dim];
                if (point[dim] > max[dim])
                    max[dim] = point[dim];
            }
        }

        double area() const
        {
            double result = max[0] - min[0];
            for (size_t dim = 1; dim < num_dim(); ++dim)
                result *= max[dim] - min[dim];
            return result;
        }

        class Iterator
        {
         private:
            double step_;
            Coordinates min_, max_, current_;

            friend struct Area;
            Iterator(double step, const Coordinates& a_min, const Coordinates& a_max) : step_(step), min_(a_min), max_(a_min), current_(a_min) { set_max(a_max); }
            Iterator() : step_(std::numeric_limits<double>::quiet_NaN()) {}

            void set_max(const Coordinates& a_max)
                {
                    for (auto dim : acmacs::range(max_.size()))
                        max_[dim] = min_[dim] + std::ceil((a_max[dim] - min_[dim]) / step_) * step_;
                }

          public:
            bool operator==(const Iterator& rhs) const
                {
                    if (std::isnan(rhs.step_))
                        return current_[0] > max_[0];
                    else if (std::isnan(step_))
                        return rhs.current_[0] > rhs.max_[0];
                    else
                        throw std::runtime_error("cannot compare Area::Iterators");
                }

            bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
            const Coordinates& operator*() const { return current_; }
            const Coordinates* operator->() const { return &current_; }

            const Iterator& operator++()
                {
                    if (current_[0] <= max_[0]) {
                        for (auto dim : acmacs::range(current_.size())) {
                            current_[dim] += step_;
                            if (current_[dim] <= max_[dim]) {
                                std::copy(min_.begin(), min_.begin() + static_cast<Coordinates::difference_type>(dim), current_.begin());
                                break;
                            }
                        }
                    }
                    return *this;
                }
        };

        Iterator begin(double step) const { return Iterator(step, min, max); }
        Iterator end() const { return Iterator{}; }

    }; // struct Area

    inline std::string to_string(const Area& area, size_t precision = 32) { return to_string(area.min, precision) + ' ' + to_string(area.max, precision); }

    inline std::ostream& operator<<(std::ostream& s, const Area& area) { return s << to_string(area, 4); }

      // ----------------------------------------------------------------------

    class LayoutInterface;

    class LayoutConstIterator
    {
      public:
        Coordinates operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const LayoutInterface& parent_;
        mutable size_t point_no_;

        LayoutConstIterator(const LayoutInterface& parent, size_t point_no) : parent_{parent}, point_no_{point_no} {}

        friend class LayoutInterface;

    }; // class LayoutConstIterator

    class LayoutDimensionConstIterator
    {
      public:
        double operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutDimensionConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            if (dimension_no_ != rhs.dimension_no_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for dimensions");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutDimensionConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const LayoutInterface& parent_;
        mutable size_t point_no_;
        const size_t dimension_no_;

        LayoutDimensionConstIterator(const LayoutInterface& parent, size_t point_no, size_t dimension_no) : parent_{parent}, point_no_{point_no}, dimension_no_{dimension_no} {}

        friend class LayoutInterface;

    }; // class LayoutDimensionConstIterator

    // ----------------------------------------------------------------------

    class LayoutInterface
    {
      public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

        // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
        // returns boundary coordinates (min and max)
        virtual Area area() const;                                  // for all points
        virtual Area area(const std::vector<size_t>& points) const; // just for the specified point indexes
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const acmacs::Vector& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

        LayoutConstIterator begin() const { return {*this, 0}; }
        LayoutConstIterator end() const { return {*this, number_of_points()}; }
        LayoutConstIterator begin_antigens(size_t /*number_of_antigens*/) const { return {*this, 0}; }
        LayoutConstIterator end_antigens(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator begin_sera(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator end_sera(size_t /*number_of_antigens*/) const { return {*this, number_of_points()}; }

        LayoutDimensionConstIterator begin_dimension(size_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_dimension(size_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }
        LayoutDimensionConstIterator begin_antigens_dimension(size_t /*number_of_antigens*/, size_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_antigens_dimension(size_t number_of_antigens, size_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator begin_sera_dimension(size_t number_of_antigens, size_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator end_sera_dimension(size_t /*number_of_antigens*/, size_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

    inline Coordinates LayoutConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.get(point_no_);
    }

    inline double LayoutDimensionConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.coordinate(point_no_, dimension_no_);
    }

      // ----------------------------------------------------------------------

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
      public:
        using Vec = std::vector<double>;

        Layout() = default;
        Layout(const Layout&) = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions) : Vec(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()), number_of_dimensions_{aNumberOfDimensions} {}
        Layout(size_t aNumberOfDimensions, const double* first, const double* last) : Vec(first, last), number_of_dimensions_{aNumberOfDimensions} {}
        Layout(const LayoutInterface& aSource) : Vec(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
        {
            if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
            }
            resize(number_of_points() * num_dim);
            number_of_dimensions_ = num_dim;
        }

        const Coordinates operator[](size_t aPointNo) const override
        {
            return {Vec::begin() + static_cast<difference_type>(aPointNo * number_of_dimensions_), Vec::begin() + static_cast<difference_type>((aPointNo + 1) * number_of_dimensions_)};
        }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {Vec::begin(), Vec::end()}; }

        void set(size_t aPointNo, const acmacs::Vector& aCoordinates) override
        {
            std::copy(aCoordinates.begin(), aCoordinates.end(), Vec::begin() + static_cast<decltype(Vec::begin())::difference_type>(aPointNo * number_of_dimensions()));
        }

        void set_nan(size_t aPointNo)
        {
            const auto first{Vec::begin() + static_cast<difference_type>(aPointNo * number_of_dimensions())}, last{first + static_cast<difference_type>(number_of_dimensions())};
            std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
        }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { Vec::operator[](point_no* number_of_dimensions() + dimension_no) = value; }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = Vec::begin() + static_cast<difference_type>((index + base) * number_of_dimensions_);
                erase(first, first + static_cast<difference_type>(number_of_dimensions_));
            }
        }

        void insert_point(size_t before, size_t base)
        {
            insert(Vec::begin() + static_cast<difference_type>((before + base) * number_of_dimensions_), number_of_dimensions_, std::numeric_limits<double>::quiet_NaN());
        }

        std::vector<std::pair<double, double>> minmax() const;

      private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>Coordinates::mean_with()<commit_after>#pragma once

#include <limits>
#include <cassert>
#include <cmath>

#include "acmacs-base/vector.hh"
#include "acmacs-base/transformation.hh"
#include "acmacs-base/size.hh"
#include "acmacs-base/stream.hh"
#include "acmacs-base/indexes.hh"
#include "acmacs-base/range.hh"

// ----------------------------------------------------------------------

namespace acmacs
{
    class Coordinates : public Vector
    {
      public:
        using Vector::Vector;

        Coordinates(Location2D loc) : Vector{loc.x(), loc.y()} {}
        Coordinates(Location3D loc) : Vector{loc.x(), loc.y(), loc.z()} {}

        Coordinates transform(const Transformation& aTransformation) const
        {
            return aTransformation.transform(static_cast<Location2D>(*this));
        }

        bool not_nan() const
        {
            return !empty() && std::all_of(begin(), end(), [](double value) -> bool { return !std::isnan(value); });
        }

        operator Location2D() const
        {
            assert(size() == 2);
            return {operator[](0), operator[](1)};
        }

        operator Location3D() const
        {
            assert(size() == 3);
            return {operator[](0), operator[](1), operator[](2)};
        }

        Coordinates& mean_with(const Coordinates& another)
        {
            for (size_t dim = 0; dim < size(); ++dim)
                (*this)[dim] = ((*this)[dim] + another[dim]) / 2.0;
            return *this;
        }

    }; // class Coordinates

    inline std::ostream& operator<<(std::ostream& s, const Coordinates& c)
    {
        stream_internal::write_to_stream(s, c, "[", "]", ", ");
        return s;
    }

    // ----------------------------------------------------------------------

    struct Area
    {
        Coordinates min, max;

        Area(const Coordinates& a_min, const Coordinates& a_max) : min(a_min), max(a_max) {}
        Area(const Coordinates& a_min) : min(a_min), max(a_min) {}

        size_t num_dim() const { return min.size(); }

        void extend(const Coordinates& point)
        {
            for (size_t dim = 0; dim < num_dim(); ++dim) {
                if (point[dim] < min[dim])
                    min[dim] = point[dim];
                if (point[dim] > max[dim])
                    max[dim] = point[dim];
            }
        }

        double area() const
        {
            double result = max[0] - min[0];
            for (size_t dim = 1; dim < num_dim(); ++dim)
                result *= max[dim] - min[dim];
            return result;
        }

        class Iterator
        {
         private:
            double step_;
            Coordinates min_, max_, current_;

            friend struct Area;
            Iterator(double step, const Coordinates& a_min, const Coordinates& a_max) : step_(step), min_(a_min), max_(a_min), current_(a_min) { set_max(a_max); }
            Iterator() : step_(std::numeric_limits<double>::quiet_NaN()) {}

            void set_max(const Coordinates& a_max)
                {
                    for (auto dim : acmacs::range(max_.size()))
                        max_[dim] = min_[dim] + std::ceil((a_max[dim] - min_[dim]) / step_) * step_;
                }

          public:
            bool operator==(const Iterator& rhs) const
                {
                    if (std::isnan(rhs.step_))
                        return current_[0] > max_[0];
                    else if (std::isnan(step_))
                        return rhs.current_[0] > rhs.max_[0];
                    else
                        throw std::runtime_error("cannot compare Area::Iterators");
                }

            bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
            const Coordinates& operator*() const { return current_; }
            const Coordinates* operator->() const { return &current_; }

            const Iterator& operator++()
                {
                    if (current_[0] <= max_[0]) {
                        for (auto dim : acmacs::range(current_.size())) {
                            current_[dim] += step_;
                            if (current_[dim] <= max_[dim]) {
                                std::copy(min_.begin(), min_.begin() + static_cast<Coordinates::difference_type>(dim), current_.begin());
                                break;
                            }
                        }
                    }
                    return *this;
                }
        };

        Iterator begin(double step) const { return Iterator(step, min, max); }
        Iterator end() const { return Iterator{}; }

    }; // struct Area

    inline std::string to_string(const Area& area, size_t precision = 32) { return to_string(area.min, precision) + ' ' + to_string(area.max, precision); }

    inline std::ostream& operator<<(std::ostream& s, const Area& area) { return s << to_string(area, 4); }

      // ----------------------------------------------------------------------

    class LayoutInterface;

    class LayoutConstIterator
    {
      public:
        Coordinates operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const LayoutInterface& parent_;
        mutable size_t point_no_;

        LayoutConstIterator(const LayoutInterface& parent, size_t point_no) : parent_{parent}, point_no_{point_no} {}

        friend class LayoutInterface;

    }; // class LayoutConstIterator

    class LayoutDimensionConstIterator
    {
      public:
        double operator*() const;
        auto& operator++()
        {
            ++point_no_;
            // do not skip disconnected points to avoid jumping over end iterator
            return *this;
        }
        bool operator==(const LayoutDimensionConstIterator& rhs) const
        {
            if (&parent_ != &rhs.parent_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for different layouts");
            if (dimension_no_ != rhs.dimension_no_)
                throw std::runtime_error("LayoutDimensionConstIterator: cannot compare iterators for dimensions");
            return point_no_ == rhs.point_no_;
        }
        bool operator!=(const LayoutDimensionConstIterator& rhs) const { return !operator==(rhs); }

      private:
        const LayoutInterface& parent_;
        mutable size_t point_no_;
        const size_t dimension_no_;

        LayoutDimensionConstIterator(const LayoutInterface& parent, size_t point_no, size_t dimension_no) : parent_{parent}, point_no_{point_no}, dimension_no_{dimension_no} {}

        friend class LayoutInterface;

    }; // class LayoutDimensionConstIterator

    // ----------------------------------------------------------------------

    class LayoutInterface
    {
      public:
        LayoutInterface() = default;
        LayoutInterface(const LayoutInterface&) = default;
        virtual ~LayoutInterface() = default;
        LayoutInterface& operator=(const LayoutInterface&) = default;

        virtual size_t number_of_points() const noexcept = 0;
        virtual size_t number_of_dimensions() const noexcept = 0;
        virtual const Coordinates operator[](size_t aPointNo) const = 0;
        const Coordinates get(size_t aPointNo) const { return operator[](aPointNo); }
        Coordinates& operator[](size_t) = delete; // use set()!
        virtual double coordinate(size_t aPointNo, size_t aDimensionNo) const = 0;
        double operator()(size_t aPointNo, size_t aDimensionNo) const { return coordinate(aPointNo, aDimensionNo); }
        virtual bool point_has_coordinates(size_t point_no) const = 0;
        virtual std::vector<double> as_flat_vector_double() const = 0;
        virtual std::vector<float> as_flat_vector_float() const = 0;

        double distance(size_t p1, size_t p2, double no_distance = std::numeric_limits<double>::quiet_NaN()) const
        {
            const auto c1 = operator[](p1);
            const auto c2 = operator[](p2);
            return (c1.not_nan() && c2.not_nan()) ? c1.distance(c2) : no_distance;
        }

        // returns indexes for min points for each dimension and max points for each dimension
        virtual std::pair<std::vector<size_t>, std::vector<size_t>> min_max_point_indexes() const;
        // returns boundary coordinates (min and max)
        virtual Area area() const;                                  // for all points
        virtual Area area(const std::vector<size_t>& points) const; // just for the specified point indexes
        virtual LayoutInterface* transform(const Transformation& aTransformation) const;
        virtual Coordinates centroid() const;

        virtual void set(size_t aPointNo, const acmacs::Vector& aCoordinates) = 0;
        virtual void set(size_t point_no, size_t dimension_no, double value) = 0;

        LayoutConstIterator begin() const { return {*this, 0}; }
        LayoutConstIterator end() const { return {*this, number_of_points()}; }
        LayoutConstIterator begin_antigens(size_t /*number_of_antigens*/) const { return {*this, 0}; }
        LayoutConstIterator end_antigens(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator begin_sera(size_t number_of_antigens) const { return {*this, number_of_antigens}; }
        LayoutConstIterator end_sera(size_t /*number_of_antigens*/) const { return {*this, number_of_points()}; }

        LayoutDimensionConstIterator begin_dimension(size_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_dimension(size_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }
        LayoutDimensionConstIterator begin_antigens_dimension(size_t /*number_of_antigens*/, size_t dimension_no) const { return {*this, 0, dimension_no}; }
        LayoutDimensionConstIterator end_antigens_dimension(size_t number_of_antigens, size_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator begin_sera_dimension(size_t number_of_antigens, size_t dimension_no) const { return {*this, number_of_antigens, dimension_no}; }
        LayoutDimensionConstIterator end_sera_dimension(size_t /*number_of_antigens*/, size_t dimension_no) const { return {*this, number_of_points(), dimension_no}; }

    }; // class LayoutInterface

    inline std::ostream& operator<<(std::ostream& s, const LayoutInterface& aLayout)
    {
        s << "Layout [";
        for (size_t no = 0; no < aLayout.number_of_points(); ++no)
            s << aLayout[no] << ' ';
        s << ']';
        return s;
    }

    inline Coordinates LayoutConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.get(point_no_);
    }

    inline double LayoutDimensionConstIterator::operator*() const
    {
        while (point_no_ < parent_.number_of_points() && !parent_.point_has_coordinates(point_no_))
            ++point_no_; // skip disconnected points
        return parent_.coordinate(point_no_, dimension_no_);
    }

      // ----------------------------------------------------------------------

    class Layout : public virtual LayoutInterface, public std::vector<double>
    {
      public:
        using Vec = std::vector<double>;

        Layout() = default;
        Layout(const Layout&) = default;
        Layout(size_t aNumberOfPoints, size_t aNumberOfDimensions) : Vec(aNumberOfPoints * aNumberOfDimensions, std::numeric_limits<double>::quiet_NaN()), number_of_dimensions_{aNumberOfDimensions} {}
        Layout(size_t aNumberOfDimensions, const double* first, const double* last) : Vec(first, last), number_of_dimensions_{aNumberOfDimensions} {}
        Layout(const LayoutInterface& aSource) : Vec(aSource.as_flat_vector_double()), number_of_dimensions_{aSource.number_of_dimensions()} {}
        Layout(const LayoutInterface& aSource, const std::vector<size_t>& aIndexes); // make layout by subsetting source
        Layout& operator=(const Layout&) = default;

        size_t number_of_points() const noexcept override { return size() / number_of_dimensions_; }
        size_t number_of_dimensions() const noexcept override { return number_of_dimensions_; }

        void change_number_of_dimensions(size_t num_dim, bool allow_dimensions_increase = false)
        {
            if (!allow_dimensions_increase && num_dim >= number_of_dimensions_) {
                throw std::runtime_error("Layout::change_number_of_dimensions: dimensions increase: " + std::to_string(number_of_dimensions_) + " --> " + std::to_string(num_dim));
                // std::cerr << "WARNING: Layout::change_number_of_dimensions: " << number_of_dimensions_ << " --> " << num_dim << '\n';
            }
            resize(number_of_points() * num_dim);
            number_of_dimensions_ = num_dim;
        }

        const Coordinates operator[](size_t aPointNo) const override
        {
            return {Vec::begin() + static_cast<difference_type>(aPointNo * number_of_dimensions_), Vec::begin() + static_cast<difference_type>((aPointNo + 1) * number_of_dimensions_)};
        }

        double coordinate(size_t aPointNo, size_t aDimensionNo) const override { return at(aPointNo * number_of_dimensions_ + aDimensionNo); }
        bool point_has_coordinates(size_t point_no) const override { return !std::isnan(coordinate(point_no, 0)); }
        std::vector<double> as_flat_vector_double() const override { return *this; }
        std::vector<float> as_flat_vector_float() const override { return {Vec::begin(), Vec::end()}; }

        void set(size_t aPointNo, const acmacs::Vector& aCoordinates) override
        {
            std::copy(aCoordinates.begin(), aCoordinates.end(), Vec::begin() + static_cast<decltype(Vec::begin())::difference_type>(aPointNo * number_of_dimensions()));
        }

        void set_nan(size_t aPointNo)
        {
            const auto first{Vec::begin() + static_cast<difference_type>(aPointNo * number_of_dimensions())}, last{first + static_cast<difference_type>(number_of_dimensions())};
            std::for_each(first, last, [](auto& target) { target = std::numeric_limits<std::decay_t<decltype(target)>>::quiet_NaN(); });
        }

        virtual void set(size_t point_no, size_t dimension_no, double value) override { Vec::operator[](point_no* number_of_dimensions() + dimension_no) = value; }

        void remove_points(const ReverseSortedIndexes& indexes, size_t base)
        {
            for (const auto index : indexes) {
                const auto first = Vec::begin() + static_cast<difference_type>((index + base) * number_of_dimensions_);
                erase(first, first + static_cast<difference_type>(number_of_dimensions_));
            }
        }

        void insert_point(size_t before, size_t base)
        {
            insert(Vec::begin() + static_cast<difference_type>((before + base) * number_of_dimensions_), number_of_dimensions_, std::numeric_limits<double>::quiet_NaN());
        }

        std::vector<std::pair<double, double>> minmax() const;

      private:
        size_t number_of_dimensions_;

    }; // class Layout

} // namespace acmacs

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <stdio.h>
#include "astutil.h"
#include "beautify.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "stmt.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

static int max(int a, int b) {
  return (a >= b) ? a : b;
}

static void setOrder(Map<ClassType*,int>& order, int& maxOrder, ClassType* ct);

static int
getOrder(Map<ClassType*,int>& order, int& maxOrder,
         ClassType* ct, Vec<ClassType*>& visit) {
  if (visit.set_in(ct))
    return 0;
  visit.set_add(ct);
  if (order.get(ct))
    return order.get(ct);
  int i = 0;
  for_fields(field, ct) {
    if (ClassType* fct = dynamic_cast<ClassType*>(field->type)) {
      if (!visit.set_in(fct) && fct->classTag != CLASS_CLASS)
        setOrder(order, maxOrder, fct);
      i = max(i, getOrder(order, maxOrder, fct, visit));
    }
  }
  return i + (ct->classTag != CLASS_CLASS);
}

static void
setOrder(Map<ClassType*,int>& order, int& maxOrder,
         ClassType* ct) {
  if (ct->classTag == CLASS_CLASS || order.get(ct))
    return;
  int i;
  Vec<ClassType*> visit;
  i = getOrder(order, maxOrder, ct, visit);
  order.put(ct, i);
  if (i > maxOrder)
    maxOrder = i;
}

#define STRSUB(x)                               \
  *ch = '\0';                                   \
  sym->cname = stringcat(sym->cname, x, ch+1);  \
  ch = sym->cname

static void legalizeCName(Symbol* sym) {
  for (char* ch = sym->cname; *ch != '\0'; ch++) {
    switch (*ch) {
    case '>': STRSUB("_GREATER_"); break;
    case '<': STRSUB("_LESS_"); break;
    case '=': STRSUB("_EQUAL_"); break;
    case '*': STRSUB("_ASTERISK_"); break;
    case '/': STRSUB("_SLASH_"); break;
    case '%': STRSUB("_PERCENT_"); break;
    case '+': STRSUB("_PLUS_"); break;
    case '-': STRSUB("_HYPHEN_"); break;
    case '^': STRSUB("_CARET_"); break;
    case '&': STRSUB("_AMPERSAND_"); break;
    case '|': STRSUB("_BAR_"); break;
    case '!': STRSUB("_EXCLAMATION_"); break;
    case '#': STRSUB("_POUND_"); break;
    case '?': STRSUB("_QUESTION_"); break;
    case '~': STRSUB("_TILDA_"); break;
    default: break;
    }
  }
}

static void codegen_header(void) {
  ChainHashMap<char*, StringHashFns, int> cnames;
  Vec<TypeSymbol*> typeSymbols;
  Vec<FnSymbol*> fnSymbols;
  Vec<VarSymbol*> varSymbols;

  chpl_main->addPragma("rename _chpl_main");

  cnames.put("abs", 1);
  cnames.put("exit", 1);
  cnames.put("_init", 1);
  cnames.put("stdin", 1);
  cnames.put("close", 1);
  cnames.put("fwrite", 1);
  cnames.put("fread", 1);
  cnames.put("main", 1);
  cnames.put("open", 1);
  cnames.put("printf", 1);
  cnames.put("quad", 1);
  cnames.put("read", 1);
  cnames.put("sleep", 1);
  cnames.put("stderr", 1);
  cnames.put("stdout", 1);
  cnames.put("write", 1);
  cnames.put("y1", 1); // this is ridiculous...
  cnames.put("log2", 1);
  cnames.put("remove", 1);
  cnames.put("fprintf", 1);
  cnames.put("clone", 1);
  cnames.put("new", 1);

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = dynamic_cast<DefExpr*>(ast)) {
      Symbol* sym = def->sym;

      if (sym->name == sym->cname)
        sym->cname = stringcpy(sym->name);

      if (char* pragma = sym->hasPragmaPrefix("rename"))
        sym->cname = stringcpy(pragma+7);

      if (VarSymbol* vs = dynamic_cast<VarSymbol*>(ast))
        if (vs->immediate)
          continue;

      legalizeCName(sym);

      // mangle symbol that is neither field nor formal if the symbol's
      // name has already been encountered
      if (!dynamic_cast<ArgSymbol*>(sym) &&
          !dynamic_cast<UnresolvedSymbol*>(sym) &&
          !dynamic_cast<ClassType*>(sym->parentScope->astParent) &&
          cnames.get(sym->cname))
        sym->cname = stringcat("_", intstring(sym->id), "_", sym->cname);

      cnames.put(sym->cname, 1);

      if (TypeSymbol* typeSymbol = dynamic_cast<TypeSymbol*>(sym)) {
        typeSymbols.add(typeSymbol);
      } else if (FnSymbol* fnSymbol = dynamic_cast<FnSymbol*>(sym)) {
        fnSymbols.add(fnSymbol);
      } else if (VarSymbol* varSymbol = dynamic_cast<VarSymbol*>(sym)) {
        if (varSymbol->parentScope->parent == rootScope)
          varSymbols.add(varSymbol);
      }
    }
  }

  qsort(varSymbols.v, varSymbols.n, sizeof(varSymbols.v[0]), compareSymbol);
  qsort(typeSymbols.v, typeSymbols.n, sizeof(typeSymbols.v[0]), compareSymbol);
  qsort(fnSymbols.v, fnSymbols.n, sizeof(fnSymbols.v[0]), compareSymbol);

  fileinfo header;
  openCFile(&header, "_chpl_header", "h");
  FILE* outfile = header.fptr;

  fprintf(outfile, "#include \"stdchpl.h\"\n");
  fprintf(outfile, "\n/*** Class Reference Types ***/\n\n");

  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    typeSymbol->codegenPrototype(outfile);
  }

  // codegen enumerated types
  fprintf(outfile, "\n/*** Enumerated Types ***/\n\n");
  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    if (dynamic_cast<EnumType*>(typeSymbol->type))
      typeSymbol->codegenDef(outfile);
  }

  // order records/unions topologically
  //   (int, int) before (int, (int, int))
  Map<ClassType*,int> order;
  int maxOrder = 0;
  forv_Vec(TypeSymbol, ts, typeSymbols) {
    if (ClassType* ct = dynamic_cast<ClassType*>(ts->type))
      setOrder(order, maxOrder, ct);
  }

  // debug
//   for (int i = 0; i < order.n; i++) {
//     if (order.v[i].key && order.v[i].value) {
//       printf("%d: %s\n", order.v[i].value, order.v[i].key->symbol->name);
//     }
//   }
//   printf("%d\n", maxOrder);

  // codegen records/unions in topological order
  fprintf(outfile, "\n/*** Records and Unions (Hierarchically) ***/\n\n");
  for (int i = 1; i <= maxOrder; i++) {
    forv_Vec(TypeSymbol, ts, typeSymbols) {
      if (ClassType* ct = dynamic_cast<ClassType*>(ts->type))
        if (order.get(ct) == i)
          ts->codegenDef(outfile);
    }
  }

  // codegen remaining types
  fprintf(outfile, "/*** Classes ***/\n\n");
  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    if (ClassType* ct = dynamic_cast<ClassType*>(typeSymbol->type))
      if (ct->classTag != CLASS_CLASS)
        continue;
    if (dynamic_cast<EnumType*>(typeSymbol->type))
      continue;
    typeSymbol->codegenDef(outfile);
  }

  fprintf(outfile, "/*** Function Prototypes ***/\n\n");
  forv_Vec(FnSymbol, fnSymbol, fnSymbols) {
    fnSymbol->codegenPrototype(outfile);
  }

  fprintf(outfile, "\n/*** Global Variables ***/\n\n");
  forv_Vec(VarSymbol, varSymbol, varSymbols) {
    varSymbol->codegenDef(outfile);
  }
  closeCFile(&header);
  beautify(&header);
}

static void
codegen_config(FILE* outfile) {
  fprintf(outfile, "void CreateConfigVarTable(void) {\n");
  fprintf(outfile, "initConfigVarTable();\n");

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = dynamic_cast<DefExpr*>(ast)) {
      VarSymbol* var = dynamic_cast<VarSymbol*>(def->sym);
      if (var && var->varClass == VAR_CONFIG) {
        fprintf(outfile, "installConfigVar(\"%s\", \"", var->name);
        fprintf(outfile, var->type->symbol->name);
        fprintf(outfile, "\", \"%s\");\n", var->getModule()->name);
      }
    }
  }

  fprintf(outfile, "if (askedToParseArgs()) {\n");
  fprintf(outfile, "  parseConfigArgs();\n");
  fprintf(outfile, "}\n");

  fprintf(outfile, "if (askedToPrintHelpMessage()) {\n");
  fprintf(outfile, "  printHelpTable();\n");
  fprintf(outfile, "  printConfigVarTable();\n");
  fprintf(outfile, "}\n");

  fprintf(outfile, "}\n");
}

void codegen(void) {
  if (no_codegen)
    return;

  fileinfo mainfile;
  openCFile(&mainfile, "_main", "c");
  fprintf(mainfile.fptr, "#include \"_chpl_header.h\"\n");

  codegen_makefile(&mainfile);

  codegen_header();

  codegen_config(mainfile.fptr);

  forv_Vec(ModuleSymbol, currentModule, allModules) {
    mysystem(stringcat("# codegen-ing module", currentModule->name),
             "generating comment for --print-commands option");

    fileinfo modulefile;
    openCFile(&modulefile, currentModule->name, "c");
    currentModule->codegenDef(modulefile.fptr);
    closeCFile(&modulefile);
    fprintf(mainfile.fptr, "#include \"%s%s\"\n", currentModule->name, ".c");
    beautify(&modulefile);
  }

  closeCFile(&mainfile);
  beautify(&mainfile);
  makeBinary();
}
<commit_msg><commit_after>#include <stdio.h>
#include "astutil.h"
#include "beautify.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "stmt.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

static int max(int a, int b) {
  return (a >= b) ? a : b;
}

static void setOrder(Map<ClassType*,int>& order, int& maxOrder, ClassType* ct);

static int
getOrder(Map<ClassType*,int>& order, int& maxOrder,
         ClassType* ct, Vec<ClassType*>& visit) {
  if (visit.set_in(ct))
    return 0;
  visit.set_add(ct);
  if (order.get(ct))
    return order.get(ct);
  int i = 0;
  for_fields(field, ct) {
    if (ClassType* fct = dynamic_cast<ClassType*>(field->type)) {
      if (!visit.set_in(fct) && fct->classTag != CLASS_CLASS)
        setOrder(order, maxOrder, fct);
      i = max(i, getOrder(order, maxOrder, fct, visit));
    }
  }
  return i + (ct->classTag != CLASS_CLASS);
}

static void
setOrder(Map<ClassType*,int>& order, int& maxOrder,
         ClassType* ct) {
  if (ct->classTag == CLASS_CLASS || order.get(ct))
    return;
  int i;
  Vec<ClassType*> visit;
  i = getOrder(order, maxOrder, ct, visit);
  order.put(ct, i);
  if (i > maxOrder)
    maxOrder = i;
}

#define STRSUB(x)                               \
  *ch = '\0';                                   \
  sym->cname = stringcat(sym->cname, x, ch+1);  \
  ch = sym->cname

static void legalizeCName(Symbol* sym) {
  for (char* ch = sym->cname; *ch != '\0'; ch++) {
    switch (*ch) {
    case '>': STRSUB("_GREATER_"); break;
    case '<': STRSUB("_LESS_"); break;
    case '=': STRSUB("_EQUAL_"); break;
    case '*': STRSUB("_ASTERISK_"); break;
    case '/': STRSUB("_SLASH_"); break;
    case '%': STRSUB("_PERCENT_"); break;
    case '+': STRSUB("_PLUS_"); break;
    case '-': STRSUB("_HYPHEN_"); break;
    case '^': STRSUB("_CARET_"); break;
    case '&': STRSUB("_AMPERSAND_"); break;
    case '|': STRSUB("_BAR_"); break;
    case '!': STRSUB("_EXCLAMATION_"); break;
    case '#': STRSUB("_POUND_"); break;
    case '?': STRSUB("_QUESTION_"); break;
    case '~': STRSUB("_TILDA_"); break;
    default: break;
    }
  }
}

static void codegen_header(void) {
  ChainHashMap<char*, StringHashFns, int> cnames;
  Vec<TypeSymbol*> typeSymbols;
  Vec<FnSymbol*> fnSymbols;
  Vec<VarSymbol*> varSymbols;

  chpl_main->addPragma("rename _chpl_main");

  cnames.put("abs", 1);
  cnames.put("exit", 1);
  cnames.put("_init", 1);
  cnames.put("stdin", 1);
  cnames.put("close", 1);
  cnames.put("fwrite", 1);
  cnames.put("fread", 1);
  cnames.put("main", 1);
  cnames.put("open", 1);
  cnames.put("printf", 1);
  cnames.put("quad", 1);
  cnames.put("read", 1);
  cnames.put("sleep", 1);
  cnames.put("stderr", 1);
  cnames.put("stdout", 1);
  cnames.put("write", 1);
  cnames.put("y1", 1); // this is ridiculous...
  cnames.put("log2", 1);
  cnames.put("remove", 1);
  cnames.put("fprintf", 1);
  cnames.put("clone", 1);
  cnames.put("new", 1);

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = dynamic_cast<DefExpr*>(ast)) {
      Symbol* sym = def->sym;

      if (sym->name == sym->cname)
        sym->cname = stringcpy(sym->name);

      if (char* pragma = sym->hasPragmaPrefix("rename"))
        sym->cname = stringcpy(pragma+7);

      if (VarSymbol* vs = dynamic_cast<VarSymbol*>(ast))
        if (vs->immediate)
          continue;

      legalizeCName(sym);

      // mangle symbol that is neither field nor formal if the symbol's
      // name has already been encountered
      if (!dynamic_cast<ArgSymbol*>(sym) &&
          !dynamic_cast<UnresolvedSymbol*>(sym) &&
          !dynamic_cast<ClassType*>(sym->parentScope->astParent) &&
          cnames.get(sym->cname))
        sym->cname = stringcat("_", sym->cname, "_", intstring(sym->id));

      cnames.put(sym->cname, 1);

      if (TypeSymbol* typeSymbol = dynamic_cast<TypeSymbol*>(sym)) {
        typeSymbols.add(typeSymbol);
      } else if (FnSymbol* fnSymbol = dynamic_cast<FnSymbol*>(sym)) {
        fnSymbols.add(fnSymbol);
      } else if (VarSymbol* varSymbol = dynamic_cast<VarSymbol*>(sym)) {
        if (varSymbol->parentScope->parent == rootScope)
          varSymbols.add(varSymbol);
      }
    }
  }

  qsort(varSymbols.v, varSymbols.n, sizeof(varSymbols.v[0]), compareSymbol);
  qsort(typeSymbols.v, typeSymbols.n, sizeof(typeSymbols.v[0]), compareSymbol);
  qsort(fnSymbols.v, fnSymbols.n, sizeof(fnSymbols.v[0]), compareSymbol);

  fileinfo header;
  openCFile(&header, "_chpl_header", "h");
  FILE* outfile = header.fptr;

  fprintf(outfile, "#include \"stdchpl.h\"\n");
  fprintf(outfile, "\n/*** Class Reference Types ***/\n\n");

  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    typeSymbol->codegenPrototype(outfile);
  }

  // codegen enumerated types
  fprintf(outfile, "\n/*** Enumerated Types ***/\n\n");
  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    if (dynamic_cast<EnumType*>(typeSymbol->type))
      typeSymbol->codegenDef(outfile);
  }

  // order records/unions topologically
  //   (int, int) before (int, (int, int))
  Map<ClassType*,int> order;
  int maxOrder = 0;
  forv_Vec(TypeSymbol, ts, typeSymbols) {
    if (ClassType* ct = dynamic_cast<ClassType*>(ts->type))
      setOrder(order, maxOrder, ct);
  }

  // debug
//   for (int i = 0; i < order.n; i++) {
//     if (order.v[i].key && order.v[i].value) {
//       printf("%d: %s\n", order.v[i].value, order.v[i].key->symbol->name);
//     }
//   }
//   printf("%d\n", maxOrder);

  // codegen records/unions in topological order
  fprintf(outfile, "\n/*** Records and Unions (Hierarchically) ***/\n\n");
  for (int i = 1; i <= maxOrder; i++) {
    forv_Vec(TypeSymbol, ts, typeSymbols) {
      if (ClassType* ct = dynamic_cast<ClassType*>(ts->type))
        if (order.get(ct) == i)
          ts->codegenDef(outfile);
    }
  }

  // codegen remaining types
  fprintf(outfile, "/*** Classes ***/\n\n");
  forv_Vec(TypeSymbol, typeSymbol, typeSymbols) {
    if (ClassType* ct = dynamic_cast<ClassType*>(typeSymbol->type))
      if (ct->classTag != CLASS_CLASS)
        continue;
    if (dynamic_cast<EnumType*>(typeSymbol->type))
      continue;
    typeSymbol->codegenDef(outfile);
  }

  fprintf(outfile, "/*** Function Prototypes ***/\n\n");
  forv_Vec(FnSymbol, fnSymbol, fnSymbols) {
    fnSymbol->codegenPrototype(outfile);
  }

  fprintf(outfile, "\n/*** Global Variables ***/\n\n");
  forv_Vec(VarSymbol, varSymbol, varSymbols) {
    varSymbol->codegenDef(outfile);
  }
  closeCFile(&header);
  beautify(&header);
}

static void
codegen_config(FILE* outfile) {
  fprintf(outfile, "void CreateConfigVarTable(void) {\n");
  fprintf(outfile, "initConfigVarTable();\n");

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = dynamic_cast<DefExpr*>(ast)) {
      VarSymbol* var = dynamic_cast<VarSymbol*>(def->sym);
      if (var && var->varClass == VAR_CONFIG) {
        fprintf(outfile, "installConfigVar(\"%s\", \"", var->name);
        fprintf(outfile, var->type->symbol->name);
        fprintf(outfile, "\", \"%s\");\n", var->getModule()->name);
      }
    }
  }

  fprintf(outfile, "if (askedToParseArgs()) {\n");
  fprintf(outfile, "  parseConfigArgs();\n");
  fprintf(outfile, "}\n");

  fprintf(outfile, "if (askedToPrintHelpMessage()) {\n");
  fprintf(outfile, "  printHelpTable();\n");
  fprintf(outfile, "  printConfigVarTable();\n");
  fprintf(outfile, "}\n");

  fprintf(outfile, "}\n");
}

void codegen(void) {
  if (no_codegen)
    return;

  fileinfo mainfile;
  openCFile(&mainfile, "_main", "c");
  fprintf(mainfile.fptr, "#include \"_chpl_header.h\"\n");

  codegen_makefile(&mainfile);

  codegen_header();

  codegen_config(mainfile.fptr);

  forv_Vec(ModuleSymbol, currentModule, allModules) {
    mysystem(stringcat("# codegen-ing module", currentModule->name),
             "generating comment for --print-commands option");

    fileinfo modulefile;
    openCFile(&modulefile, currentModule->name, "c");
    currentModule->codegenDef(modulefile.fptr);
    closeCFile(&modulefile);
    fprintf(mainfile.fptr, "#include \"%s%s\"\n", currentModule->name, ".c");
    beautify(&modulefile);
  }

  closeCFile(&mainfile);
  beautify(&mainfile);
  makeBinary();
}
<|endoftext|>


<commit_before>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * 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 "command_pool.hpp"
#include "device.hpp"

namespace Vulkan
{
CommandPool::CommandPool(Device *device_, uint32_t queue_family_index)
    : device(device_), table(&device_->get_device_table())
{
	VkCommandPoolCreateInfo info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
	info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
	info.queueFamilyIndex = queue_family_index;
	table->vkCreateCommandPool(device->get_device(), &info, nullptr, &pool);
}

CommandPool::CommandPool(CommandPool &&other) noexcept
{
	*this = std::move(other);
}

CommandPool &CommandPool::operator=(CommandPool &&other) noexcept
{
	if (this != &other)
	{
		device = other.device;
		table = other.table;
		if (!buffers.empty())
			table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
		if (pool != VK_NULL_HANDLE)
			table->vkDestroyCommandPool(device->get_device(), pool, nullptr);

		pool = VK_NULL_HANDLE;
		buffers.clear();
		std::swap(pool, other.pool);
		std::swap(buffers, other.buffers);
		index = other.index;
		other.index = 0;
#ifdef VULKAN_DEBUG
		in_flight.clear();
		std::swap(in_flight, other.in_flight);
#endif
	}
	return *this;
}

CommandPool::~CommandPool()
{
	if (!buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
	if (!secondary_buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, secondary_buffers.size(), secondary_buffers.data());
	if (pool != VK_NULL_HANDLE)
		table->vkDestroyCommandPool(device->get_device(), pool, nullptr);
}

void CommandPool::signal_submitted(VkCommandBuffer cmd)
{
#ifdef VULKAN_DEBUG
	VK_ASSERT(in_flight.find(cmd) != end(in_flight));
	in_flight.erase(cmd);
#else
	(void)cmd;
#endif
}

VkCommandBuffer CommandPool::request_secondary_command_buffer()
{
	if (secondary_index < secondary_buffers.size())
	{
		auto ret = secondary_buffers[secondary_index++];
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(ret) == end(in_flight));
		in_flight.insert(ret);
#endif
		return ret;
	}
	else
	{
		VkCommandBuffer cmd;
		VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
		info.commandPool = pool;
		info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
		info.commandBufferCount = 1;

		table->vkAllocateCommandBuffers(device->get_device(), &info, &cmd);
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(cmd) == end(in_flight));
		in_flight.insert(cmd);
#endif
		secondary_buffers.push_back(cmd);
		secondary_index++;
		return cmd;
	}
}

VkCommandBuffer CommandPool::request_command_buffer()
{
	if (index < buffers.size())
	{
		auto ret = buffers[index++];
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(ret) == end(in_flight));
		in_flight.insert(ret);
#endif
		return ret;
	}
	else
	{
		VkCommandBuffer cmd;
		VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
		info.commandPool = pool;
		info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
		info.commandBufferCount = 1;

		table->vkAllocateCommandBuffers(device->get_device(), &info, &cmd);
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(cmd) == end(in_flight));
		in_flight.insert(cmd);
#endif
		buffers.push_back(cmd);
		index++;
		return cmd;
	}
}

void CommandPool::begin()
{
#ifdef VULKAN_DEBUG
	VK_ASSERT(in_flight.empty());
#endif
	if (index > 0 || secondary_index > 0)
		table->vkResetCommandPool(device->get_device(), pool, 0);
	index = 0;
	secondary_index = 0;
}

void CommandPool::trim()
{
	table->vkResetCommandPool(device->get_device(), pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
	if (!buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
	if (!secondary_buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, secondary_buffers.size(), secondary_buffers.data());
	buffers.clear();
	secondary_buffers.clear();
	if (device->get_device_features().supports_maintenance_1)
		table->vkTrimCommandPoolKHR(device->get_device(), pool, 0);
}
}
<commit_msg>Don't create command pool with ignored family index.<commit_after>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * 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 "command_pool.hpp"
#include "device.hpp"

namespace Vulkan
{
CommandPool::CommandPool(Device *device_, uint32_t queue_family_index)
    : device(device_), table(&device_->get_device_table())
{
	VkCommandPoolCreateInfo info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
	info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
	info.queueFamilyIndex = queue_family_index;
	if (queue_family_index != VK_QUEUE_FAMILY_IGNORED)
		table->vkCreateCommandPool(device->get_device(), &info, nullptr, &pool);
}

CommandPool::CommandPool(CommandPool &&other) noexcept
{
	*this = std::move(other);
}

CommandPool &CommandPool::operator=(CommandPool &&other) noexcept
{
	if (this != &other)
	{
		device = other.device;
		table = other.table;
		if (!buffers.empty())
			table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
		if (pool != VK_NULL_HANDLE)
			table->vkDestroyCommandPool(device->get_device(), pool, nullptr);

		pool = VK_NULL_HANDLE;
		buffers.clear();
		std::swap(pool, other.pool);
		std::swap(buffers, other.buffers);
		index = other.index;
		other.index = 0;
#ifdef VULKAN_DEBUG
		in_flight.clear();
		std::swap(in_flight, other.in_flight);
#endif
	}
	return *this;
}

CommandPool::~CommandPool()
{
	if (!buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
	if (!secondary_buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, secondary_buffers.size(), secondary_buffers.data());
	if (pool != VK_NULL_HANDLE)
		table->vkDestroyCommandPool(device->get_device(), pool, nullptr);
}

void CommandPool::signal_submitted(VkCommandBuffer cmd)
{
#ifdef VULKAN_DEBUG
	VK_ASSERT(in_flight.find(cmd) != end(in_flight));
	in_flight.erase(cmd);
#else
	(void)cmd;
#endif
}

VkCommandBuffer CommandPool::request_secondary_command_buffer()
{
	VK_ASSERT(pool != VK_NULL_HANDLE);

	if (secondary_index < secondary_buffers.size())
	{
		auto ret = secondary_buffers[secondary_index++];
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(ret) == end(in_flight));
		in_flight.insert(ret);
#endif
		return ret;
	}
	else
	{
		VkCommandBuffer cmd;
		VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
		info.commandPool = pool;
		info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
		info.commandBufferCount = 1;

		table->vkAllocateCommandBuffers(device->get_device(), &info, &cmd);
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(cmd) == end(in_flight));
		in_flight.insert(cmd);
#endif
		secondary_buffers.push_back(cmd);
		secondary_index++;
		return cmd;
	}
}

VkCommandBuffer CommandPool::request_command_buffer()
{
	VK_ASSERT(pool != VK_NULL_HANDLE);

	if (index < buffers.size())
	{
		auto ret = buffers[index++];
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(ret) == end(in_flight));
		in_flight.insert(ret);
#endif
		return ret;
	}
	else
	{
		VkCommandBuffer cmd;
		VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
		info.commandPool = pool;
		info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
		info.commandBufferCount = 1;

		table->vkAllocateCommandBuffers(device->get_device(), &info, &cmd);
#ifdef VULKAN_DEBUG
		VK_ASSERT(in_flight.find(cmd) == end(in_flight));
		in_flight.insert(cmd);
#endif
		buffers.push_back(cmd);
		index++;
		return cmd;
	}
}

void CommandPool::begin()
{
	if (pool == VK_NULL_HANDLE)
		return;

#ifdef VULKAN_DEBUG
	VK_ASSERT(in_flight.empty());
#endif
	if (index > 0 || secondary_index > 0)
		table->vkResetCommandPool(device->get_device(), pool, 0);
	index = 0;
	secondary_index = 0;
}

void CommandPool::trim()
{
	if (pool == VK_NULL_HANDLE)
		return;

	table->vkResetCommandPool(device->get_device(), pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
	if (!buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, buffers.size(), buffers.data());
	if (!secondary_buffers.empty())
		table->vkFreeCommandBuffers(device->get_device(), pool, secondary_buffers.size(), secondary_buffers.data());
	buffers.clear();
	secondary_buffers.clear();
	if (device->get_device_features().supports_maintenance_1)
		table->vkTrimCommandPoolKHR(device->get_device(), pool, 0);
}
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cmakehighlighter.h"

#include <QRegExp>
#include <QTextDocument>

using namespace CMakeProjectManager::Internal;

static bool isVariable(const QByteArray &word)
{
    if (word.length() < 4) // must be at least "${.}"
        return false;
    return word.startsWith("${") && word.endsWith('}');
}

CMakeHighlighter::CMakeHighlighter(QTextDocument *document) :
    TextEditor::SyntaxHighlighter(document)
{
    static QVector<TextEditor::TextStyle> categories;
    if (categories.isEmpty()) {
        categories << TextEditor::C_LABEL  // variables
                   << TextEditor::C_KEYWORD   // functions
                   << TextEditor::C_COMMENT
                   << TextEditor::C_STRING
                   << TextEditor::C_VISUAL_WHITESPACE;
    }
    setTextFormatCategories(categories);
}

void CMakeHighlighter::highlightBlock(const QString &text)
{
    QByteArray buf;
    bool inCommentMode = false;
    bool inStringMode = (previousBlockState() == 1);

    QTextCharFormat emptyFormat;
    int i=0;
    for (i=0; i < text.length(); i++) {
        char c = text.at(i).toLatin1();
        if (inCommentMode) {
            setFormat(i, 1, formatForCategory(CMakeCommentFormat));
        } else {
            if (c == '#') {
                if (!inStringMode) {
                    inCommentMode = true;
                    setFormat(i, 1, formatForCategory(CMakeCommentFormat));
                    buf.clear();
                } else {
                    buf += c;
                }
            } else if (c == '(') {
                if (!inStringMode) {
                    if (!buf.isEmpty())
                        setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeFunctionFormat));
                    buf.clear();
                } else {
                    buf += c;
                }
            } else if (text.at(i).isSpace()) {
                if (!inStringMode)
                    buf.clear();
                else
                    buf += c;
            } else if (c == '\"') {
                buf += c;
                if (inStringMode) {
                    setFormat(i + 1 - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
                    buf.clear();
                } else {
                    setFormat(i, 1, formatForCategory(CMakeStringFormat));
                }
                inStringMode = !inStringMode;
            } else if (c == '\\') {
                setFormat(i, 1, emptyFormat);
                buf += c;
                i++;
                if (i < text.length()) {
                    text.at(i);
                    setFormat(i, 1, emptyFormat);
                    buf += c;
                }
            } else if (c == '$') {
                if (inStringMode)
                    setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
                buf.clear();
                buf += c;
                setFormat(i, 1, emptyFormat);
            } else if (c == '}') {
                buf += c;
                if (isVariable(buf)) {
                    setFormat(i + 1 - buf.length(), buf.length(), formatForCategory(CMakeVariableFormat));
                    buf.clear();
                }
            } else {
                buf += c;
                setFormat(i, 1, emptyFormat);
            }
        }
    }

    if (inStringMode) {
        setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
        setCurrentBlockState(1);
    } else {
        setCurrentBlockState(0);
    }

    applyFormatToSpaces(text, formatForCategory(CMakeVisualWhiteSpaceFormat));
}

<commit_msg>CMake: Remove statement that has no effect<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cmakehighlighter.h"

#include <QRegExp>
#include <QTextDocument>

using namespace CMakeProjectManager::Internal;

static bool isVariable(const QByteArray &word)
{
    if (word.length() < 4) // must be at least "${.}"
        return false;
    return word.startsWith("${") && word.endsWith('}');
}

CMakeHighlighter::CMakeHighlighter(QTextDocument *document) :
    TextEditor::SyntaxHighlighter(document)
{
    static QVector<TextEditor::TextStyle> categories;
    if (categories.isEmpty()) {
        categories << TextEditor::C_LABEL  // variables
                   << TextEditor::C_KEYWORD   // functions
                   << TextEditor::C_COMMENT
                   << TextEditor::C_STRING
                   << TextEditor::C_VISUAL_WHITESPACE;
    }
    setTextFormatCategories(categories);
}

void CMakeHighlighter::highlightBlock(const QString &text)
{
    QByteArray buf;
    bool inCommentMode = false;
    bool inStringMode = (previousBlockState() == 1);

    QTextCharFormat emptyFormat;
    int i=0;
    for (i=0; i < text.length(); i++) {
        char c = text.at(i).toLatin1();
        if (inCommentMode) {
            setFormat(i, 1, formatForCategory(CMakeCommentFormat));
        } else {
            if (c == '#') {
                if (!inStringMode) {
                    inCommentMode = true;
                    setFormat(i, 1, formatForCategory(CMakeCommentFormat));
                    buf.clear();
                } else {
                    buf += c;
                }
            } else if (c == '(') {
                if (!inStringMode) {
                    if (!buf.isEmpty())
                        setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeFunctionFormat));
                    buf.clear();
                } else {
                    buf += c;
                }
            } else if (text.at(i).isSpace()) {
                if (!inStringMode)
                    buf.clear();
                else
                    buf += c;
            } else if (c == '\"') {
                buf += c;
                if (inStringMode) {
                    setFormat(i + 1 - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
                    buf.clear();
                } else {
                    setFormat(i, 1, formatForCategory(CMakeStringFormat));
                }
                inStringMode = !inStringMode;
            } else if (c == '\\') {
                setFormat(i, 1, emptyFormat);
                buf += c;
                i++;
                if (i < text.length()) {
                    setFormat(i, 1, emptyFormat);
                    buf += c;
                }
            } else if (c == '$') {
                if (inStringMode)
                    setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
                buf.clear();
                buf += c;
                setFormat(i, 1, emptyFormat);
            } else if (c == '}') {
                buf += c;
                if (isVariable(buf)) {
                    setFormat(i + 1 - buf.length(), buf.length(), formatForCategory(CMakeVariableFormat));
                    buf.clear();
                }
            } else {
                buf += c;
                setFormat(i, 1, emptyFormat);
            }
        }
    }

    if (inStringMode) {
        setFormat(i - buf.length(), buf.length(), formatForCategory(CMakeStringFormat));
        setCurrentBlockState(1);
    } else {
        setCurrentBlockState(0);
    }

    applyFormatToSpaces(text, formatForCategory(CMakeVisualWhiteSpaceFormat));
}

<|endoftext|>


<commit_before>//! Copyright (c) 2013 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h>
#include "sl_test_header.h"

test_framework_t::test_framework_t(void)
{
}

test_framework_t::~test_framework_t(void)
{
}

test_framework_t&
test_framework_t::singleton(void)
{
  static test_framework_t _s_test;

  return _s_test;
}

void
test_framework_t::run(void)
{
  fprintf(stdout, "begin testing for slib++ ...\n");

  size_t size = case_list_.size();
  for (size_t i = 0; i < size; ++i) {
    fprintf(stdout, "\ttest %s module : ", case_list_[i].name_);
    case_list_[i].test_();
    fprintf(stdout, "passed !!!\n");
  }

  fprintf(stdout, "end testing for slib++ ...\n");
}

bool
test_framework_t::register_test(const char* name, void (*test)(void))
{
  if (NULL == name || NULL == test)
    return false;

  case_list_.push_back(test_case_t(name, test));
  return true;
}

int
main(int argc, char* argv[])
{
  test_framework_t::singleton().run();

  return 0;
}
<commit_msg>updated display information for test framework of slib++<commit_after>//! Copyright (c) 2013 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h>
#include "sl_test_header.h"

test_framework_t::test_framework_t(void)
{
}

test_framework_t::~test_framework_t(void)
{
}

test_framework_t&
test_framework_t::singleton(void)
{
  static test_framework_t _s_test;

  return _s_test;
}

void
test_framework_t::run(void)
{
  fprintf(stdout, "begin testing for slib++ ...\n");

  size_t size = case_list_.size();
  for (size_t i = 0; i < size; ++i) {
    fprintf(stdout, "\ttesting for %s module : \n", case_list_[i].name_);
    case_list_[i].test_();
    fprintf(stdout, "\ttesting passed !!!\n\n");
  }

  fprintf(stdout, "end testing for slib++ ...\n");
}

bool
test_framework_t::register_test(const char* name, void (*test)(void))
{
  if (NULL == name || NULL == test)
    return false;

  case_list_.push_back(test_case_t(name, test));
  return true;
}

int
main(int argc, char* argv[])
{
  test_framework_t::singleton().run();

  return 0;
}
<|endoftext|>


<commit_before>#include "Element.h"
#include "Feeder.h"
#include "IfBlock.h"
#include "Import.h"
#include "Pipeline.h"
#include "CommandLine.h"
#include "Comment.h"
using namespace std;

IfBlock::IfBlock(Feeder *f, Environment *env) : Element(f,env)
{
}

IfBlock::~IfBlock()
{
}

/* IfBlock means an if-then-else chunk in usual programing languages.
 * ex)

| commandline1	    <- if
	commandline2
| commandline2	    <- else if
	commandline3
| otherwise	       <- else
	commandline4

commandline5	      <- out of if block

The other purpose to use IfBlock is the cancel of exit statuses

| seq '1' '1000000000' >>= head

Though the head command invokes SIGPIPE error of the seq command,
"|" cancels this failure in this case.
However, this technique should be carefully used.
 */
bool IfBlock::parse(void)
{
	m_feeder->getPos(&m_start_line, &m_start_char);

	int indent = m_feeder->countIndent();

	m_feeder->blank(NULL);
	// detect the first condition
	if(! m_feeder->str("?")){
		m_feeder->setPos(m_start_line, m_start_char);
		return false;
	}

	while(1){
		// condition -> many (pipeline or commandline) -> condition ->...
		m_feeder->blank(NULL);

		if(m_feeder->str("otherwise")){
			m_nodes.push_back(NULL); // dummy
		}else if(add(new Pipeline(m_feeder,m_env))){
			((Pipeline *)m_nodes.back())->setIfFlag();
		}
		else if(add(new CommandLine(m_feeder,m_env))){
			((CommandLine *)m_nodes.back())->setIfFlag();
		}else{
			m_feeder->setPos(m_start_line, m_start_char);
			return false;
		}

		m_is_cond_node.push_back(true);

/*
		if(m_feeder->atEnd()){
			m_feeder->getPos(&m_end_line, &m_end_char);
			return true;
		}
*/

		//while(add(new Comment(m_feeder,m_env))){ }

		int sub_indent = m_feeder->countIndent();

		// end of the if block
		if(sub_indent < indent){
			break;
		}

		// found another condition
		if( indent == sub_indent){
			m_feeder->blank(NULL);
			if(m_feeder->str("?")){
				// another condition
				continue;
			}else{
				break; // end of the if block
			}
		}

		// attempt to search procedures related to the condition
		while(sub_indent > indent){
			m_feeder->blank(NULL);

			if(	add(new IfBlock(m_feeder,m_env))
				|| add(new Pipeline(m_feeder,m_env))
			 	|| add(new CommandLine(m_feeder,m_env))){

				m_is_cond_node.push_back(false);
/*
				if(m_feeder->atEnd()){
					m_feeder->getPos(&m_end_line, &m_end_char);
					return true;
				}
*/
				sub_indent = m_feeder->countIndent();
			}else{
				m_feeder->setPos(m_start_line, m_start_char);
				return false;
			}
		}

		// after procedures related to the condition
		if(sub_indent < indent){
			m_feeder->getPos(&m_end_line, &m_end_char);
			break;
		}

		m_feeder->getPos(&m_end_line, &m_end_char);
		// next condition
		m_feeder->blank(NULL);
		// detect the first condition
		if(! m_feeder->str("|")){
			m_feeder->setPos(m_end_line, m_end_char);
			break;
		}
	}
	m_feeder->getPos(&m_end_line, &m_end_char);

	return true;
}

int IfBlock::exec(void)
{
	if(m_nodes.size() != m_is_cond_node.size()){
		m_error_msg = "BUG: IfBlock internal error";
		throw this;
	}

	int exit_status = 0;
	bool skip = false;
	bool match = false;
	for(int i=0;i<m_nodes.size();i++){
		if(m_is_cond_node[i]){ // cond node
			if(match) // already matched
				break;

			if(m_nodes[i] == NULL || m_nodes[i]->exec() == 0){
				match = true;
				skip = false;
			}else
				skip = true;

		}else{ // other node
			if(!skip)
				m_nodes[i]->exec();
		}
	}
/*
	for(auto &c : m_nodes){
	}
*/
	return exit_status;
}
<commit_msg>Modify old comment<commit_after>#include "Element.h"
#include "Feeder.h"
#include "IfBlock.h"
#include "Import.h"
#include "Pipeline.h"
#include "CommandLine.h"
#include "Comment.h"
using namespace std;

IfBlock::IfBlock(Feeder *f, Environment *env) : Element(f,env)
{
}

IfBlock::~IfBlock()
{
}

/* IfBlock means an if-then-else chunk in usual programing languages.
 * ex)

? commandline1	    <- if
	commandline2
| commandline2	    <- else if
	commandline3
| otherwise	       <- else
	commandline4

commandline5	      <- out of if block

The other purpose to use IfBlock is the cancel of exit statuses

? seq '1' '1000000000' >>= head

Though the head command invokes SIGPIPE error of the seq command,
"|" cancels this failure in this case.
However, this technique should be carefully used.
 */
bool IfBlock::parse(void)
{
	m_feeder->getPos(&m_start_line, &m_start_char);

	int indent = m_feeder->countIndent();

	m_feeder->blank(NULL);
	// detect the first condition
	if(! m_feeder->str("?")){
		m_feeder->setPos(m_start_line, m_start_char);
		return false;
	}

	while(1){
		// condition -> many (pipeline or commandline) -> condition ->...
		m_feeder->blank(NULL);

		if(m_feeder->str("otherwise")){
			m_nodes.push_back(NULL); // dummy
		}else if(add(new Pipeline(m_feeder,m_env))){
			((Pipeline *)m_nodes.back())->setIfFlag();
		}
		else if(add(new CommandLine(m_feeder,m_env))){
			((CommandLine *)m_nodes.back())->setIfFlag();
		}else{
			m_feeder->setPos(m_start_line, m_start_char);
			return false;
		}

		m_is_cond_node.push_back(true);

		//while(add(new Comment(m_feeder,m_env))){ }

		int sub_indent = m_feeder->countIndent();

		// end of the if block
		if(sub_indent < indent){
			break;
		}

		// found another condition
		if( indent == sub_indent){
			m_feeder->blank(NULL);
			if(m_feeder->str("?")){
				// another condition
				continue;
			}else{
				break; // end of the if block
			}
		}

		// attempt to search procedures related to the condition
		while(sub_indent > indent){
			m_feeder->blank(NULL);

			if(	add(new IfBlock(m_feeder,m_env))
				|| add(new Pipeline(m_feeder,m_env))
			 	|| add(new CommandLine(m_feeder,m_env))){

				m_is_cond_node.push_back(false);
				sub_indent = m_feeder->countIndent();
			}else{
				m_feeder->setPos(m_start_line, m_start_char);
				return false;
			}
		}

		// after procedures related to the condition
		if(sub_indent < indent){
			m_feeder->getPos(&m_end_line, &m_end_char);
			break;
		}

		m_feeder->getPos(&m_end_line, &m_end_char);
		// next condition
		m_feeder->blank(NULL);
		// detect the first condition
		if(! m_feeder->str("|")){
			m_feeder->setPos(m_end_line, m_end_char);
			break;
		}
	}
	m_feeder->getPos(&m_end_line, &m_end_char);

	return true;
}

int IfBlock::exec(void)
{
	if(m_nodes.size() != m_is_cond_node.size()){
		m_error_msg = "BUG: IfBlock internal error";
		throw this;
	}

	int exit_status = 0;
	bool skip = false;
	bool match = false;
	for(int i=0;i<m_nodes.size();i++){
		if(m_is_cond_node[i]){ // cond node
			if(match) // already matched
				break;

			if(m_nodes[i] == NULL || m_nodes[i]->exec() == 0){
				match = true;
				skip = false;
			}else
				skip = true;

		}else{ // other node
			if(!skip)
				m_nodes[i]->exec();
		}
	}
/*
	for(auto &c : m_nodes){
	}
*/
	return exit_status;
}
<|endoftext|>