<commit_before>/*
    Copyright 2017 Harald Sitter <sitter@kde.org>

    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) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

#include <QObject>
#include <QtTest>

#include <KConfig>
#include <KConfigGroup>
#include <KIconLoader>

#include "testhelpers.h"

/**
 * Represents icon directory to conduct simple icon lookup within.
 */
class Dir
{
public:
    Dir(const KConfigGroup &cg, const QString &themeDir_)
        : exists(checkExist(cg))
        , themeDir(themeDir_)
        , path(cg.name())
        , size(cg.readEntry("Size", 0))
        , contextString(cg.readEntry("Context", QString()))
        , context(parseContext(contextString))
        , type(parseType(cg.readEntry("Type", QString("Threshold"))))
    {
        QVERIFY2(context != -1,
                 QString("Don't know how to handle 'Context=%1' of config group '[%2]'").arg(contextString, cg.name()).toLatin1());
    }

    static void verify(const KConfigGroup &cg)
    {
        QVERIFY2(cg.exists(),
                 QString("The theme's 'Directories' specifies '%1' as directory which appears to"
                         " have no associated group entry '[%1]'").arg(cg.name()).toLatin1());
    }

    static bool checkExist(const KConfigGroup &cg)
    {
        verify(cg); // extra func since QVERIFY2 is a return
        return cg.isValid();
    }

    static QMetaEnum findEnum(const char *name)
    {
        auto mo = KIconLoader::staticMetaObject;
        for (int i = 0; i < mo.enumeratorCount(); ++i) {
            auto enumerator = mo.enumerator(i);
            if (strcmp(enumerator.name(), name) == 0) {
                return KIconLoader::staticMetaObject.enumerator(i);
            }
        }
        Q_ASSERT(false); // failed to resolve enum
        return QMetaEnum();
    }

    static QMetaEnum typeEnum()
    {
        static auto e = findEnum("Type");
        return e;
    }

    KIconLoader::Context parseContext(const QString &string)
    {
        // Can't use QMetaEnum as the enum names are singular, the entry values are plural though.
        static QHash<QString, int> hash {
            { QStringLiteral("Actions"), KIconLoader::Action },
            { QStringLiteral("Applications"), KIconLoader::Application },
            { QStringLiteral("Categories"), KIconLoader::Category },
            { QStringLiteral("Devices"), KIconLoader::Device },
            { QStringLiteral("Emblems"), KIconLoader::Emblem },
            { QStringLiteral("Emotes"), KIconLoader::Emote },
            { QStringLiteral("MimeTypes"), KIconLoader::MimeType },
            { QStringLiteral("Places"), KIconLoader::Place },
            { QStringLiteral("Status"), KIconLoader::StatusIcon },
        };
        auto value = hash.value(string, -1);
        return (KIconLoader::Context)value;
    }

    KIconLoader::Type parseType(const QString &string)
    {
        bool ok;
        auto v = (KIconLoader::Type)typeEnum().keyToValue(string.toLatin1(), &ok);
        Q_ASSERT(ok);
        return v;
    }

    /**
     * @returns list of all icon's fileinfo (first level only, selected types
     *          only)
     */
    QList<QFileInfo> allIcons()
    {
        QList<QFileInfo> icons;
        auto iconDir = QString("%1/%2").arg(themeDir).arg(path);
        QDirIterator it(iconDir);
        while (it.hasNext()) {
            it.next();
            auto suffix = it.fileInfo().suffix();
            if (suffix != "svg" && suffix != "svgz" && suffix != "png") {
                continue; // Probably not an icon.
            }
            icons << it.fileInfo();
        }
        return icons;
    }

    bool exists;
    QString themeDir;
    QString path;
    uint size;
    QString contextString;
    KIconLoader::Context context;
    KIconLoader::Type type;
};

// Declare so we can put them into the QTest data table.
Q_DECLARE_METATYPE(KIconLoader::Context)
Q_DECLARE_METATYPE(Dir*)

class ScalableTest : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    // NB: test_scalable_data leaks Dir*. Should this test grow more slots it may be wise to
    //     introduce a cleanup() to make sure the test doesn't OOM.

    void test_scalable_data()
    {
        for (auto dir : ICON_DIRS) {
            auto themeDir = PROJECT_SOURCE_DIR + QStringLiteral("/") + dir;

            QHash<KIconLoader::Context, QList<Dir *>> contextHash;
            QHash<KIconLoader::Context, QString> contextStringHash;

            KConfig config(themeDir + "/index.theme");
            auto directoryPaths = config.group("Icon Theme").readEntry("Directories", QString()).split(",");
            QVERIFY(!directoryPaths.isEmpty());
            for (auto directoryPath : directoryPaths) {
                auto dir = new Dir(config.group(directoryPath), themeDir);
                contextHash[dir->context].append(dir);
                contextStringHash[dir->context] = (dir->contextString);
            }

            QTest::addColumn<KIconLoader::Context>("context");
            QTest::addColumn<QList<Dir *>>("dirs");

            for (auto key : contextHash.keys()) {
                if (key != KIconLoader::Application) {
                    qDebug() << "Only testing Application context for now.";
                    continue;
                }
                // FIXME: go through qenum to stringify the bugger
                // Gets rid of the stupid second hash
                auto contextId = QString(QLatin1String(dir) + ":" + contextStringHash[key]).toLatin1();
                QTest::newRow(contextId) << key << contextHash[key];
            }
        }
    }

    void test_scalable()
    {
        QFETCH(KIconLoader::Context, context);
        QFETCH(QList<Dir *>, dirs);

        QList<Dir *> fixedDirs;
        QList<Dir *> scalableDirs;
        for (auto dir : dirs) {
            switch (dir->type) {
            case KIconLoader::Scalable:
                scalableDirs << dir;
                break;
            case KIconLoader::Fixed:
                fixedDirs << dir;
                break;
            case KIconLoader::Threshold:
                QVERIFY2(false, "Test does not support threshold icons right now.");
            }
        }

        // FIXME: context should be translated through qenum
        switch (context) {
        case KIconLoader::Application:
            // Treat this as a problem.
            QVERIFY2(!scalableDirs.empty(), "This icon context has no scalable directory at all!");
            break;
        default:
            qWarning() << "All context but Application are whitelisted from having a scalable directory.";
            return;
        }

        QStringList fixedIcons;
        for (auto dir : fixedDirs) {
            for (auto iconInfo : dir->allIcons()) {
                fixedIcons << iconInfo.completeBaseName();
            }
        }

        QHash<QString, QList<QFileInfo>> scalableIcons;
        for (auto dir : scalableDirs) {
            for (auto iconInfo : dir->allIcons()) {
                scalableIcons[iconInfo.completeBaseName()].append(iconInfo);
            }
        }

        QStringList notScalableIcons;
        for (auto fixed : fixedIcons) {
            if (scalableIcons.keys().contains(fixed)) {
                continue;
            }
            notScalableIcons << fixed;
        }

        // Assert that each icon has a scalable variant.
        if (notScalableIcons.empty()) {
            return;
        }
        QFAIL(QString("The following icons are not available in a scalable directory:\n  %1")
              .arg(notScalableIcons.join("\n  "))
              .toLatin1());
    }

    void test_scalableDuplicates_data()
    {
        test_scalable_data();
    }

    void test_scalableDuplicates()
    {
        QFETCH(QList<Dir *>, dirs);

        QList<Dir *> scalableDirs;
        for (auto dir : dirs) {
            switch (dir->type) {
            case KIconLoader::Scalable:
                scalableDirs << dir;
                break;
            case KIconLoader::Fixed:
                // Not of interest in this test.
                break;
            case KIconLoader::Threshold:
                QVERIFY2(false, "Test does not support threshold icons right now.");
            }
        }

        QHash<QString, QList<QFileInfo>> scalableIcons;
        for (auto dir : scalableDirs) {
            for (auto iconInfo : dir->allIcons()) {
                scalableIcons[iconInfo.completeBaseName()].append(iconInfo);
            }
        }

        QHash<QString, QList<QFileInfo>> duplicatedScalableIcons;
        for (auto icon: scalableIcons.keys()) {
            auto list = scalableIcons[icon];
            if (list.size() > 1) {
                duplicatedScalableIcons[icon] = list;
            }
        }

        // Assert that there is only one scalable version per icon name.
        // Otherwise apps/32/klipper.svg OR apps/48/klipper.svg may be used.
        if (!duplicatedScalableIcons.empty()) {
            QString msg;
            QTextStream stream(&msg);
            stream << "Duplicated scalable icons:" << endl;
            for (auto icon : duplicatedScalableIcons.keys()) {
                stream << QString("  %1:").arg(icon) << endl;
                for (auto info : duplicatedScalableIcons[icon]) {
                    stream << QString("    %1").arg(info.absoluteFilePath()) << endl;
                }
            }
            QFAIL(msg.toLatin1());
        }
    }
};

QTEST_GUILESS_MAIN(ScalableTest)

#include "scalabletest.moc"
<commit_msg>remove duplicates from unscalable icons list<commit_after>/*
    Copyright 2017 Harald Sitter <sitter@kde.org>

    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) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

#include <QObject>
#include <QtTest>

#include <KConfig>
#include <KConfigGroup>
#include <KIconLoader>

#include "testhelpers.h"

/**
 * Represents icon directory to conduct simple icon lookup within.
 */
class Dir
{
public:
    Dir(const KConfigGroup &cg, const QString &themeDir_)
        : exists(checkExist(cg))
        , themeDir(themeDir_)
        , path(cg.name())
        , size(cg.readEntry("Size", 0))
        , contextString(cg.readEntry("Context", QString()))
        , context(parseContext(contextString))
        , type(parseType(cg.readEntry("Type", QString("Threshold"))))
    {
        QVERIFY2(context != -1,
                 QString("Don't know how to handle 'Context=%1' of config group '[%2]'").arg(contextString, cg.name()).toLatin1());
    }

    static void verify(const KConfigGroup &cg)
    {
        QVERIFY2(cg.exists(),
                 QString("The theme's 'Directories' specifies '%1' as directory which appears to"
                         " have no associated group entry '[%1]'").arg(cg.name()).toLatin1());
    }

    static bool checkExist(const KConfigGroup &cg)
    {
        verify(cg); // extra func since QVERIFY2 is a return
        return cg.isValid();
    }

    static QMetaEnum findEnum(const char *name)
    {
        auto mo = KIconLoader::staticMetaObject;
        for (int i = 0; i < mo.enumeratorCount(); ++i) {
            auto enumerator = mo.enumerator(i);
            if (strcmp(enumerator.name(), name) == 0) {
                return KIconLoader::staticMetaObject.enumerator(i);
            }
        }
        Q_ASSERT(false); // failed to resolve enum
        return QMetaEnum();
    }

    static QMetaEnum typeEnum()
    {
        static auto e = findEnum("Type");
        return e;
    }

    KIconLoader::Context parseContext(const QString &string)
    {
        // Can't use QMetaEnum as the enum names are singular, the entry values are plural though.
        static QHash<QString, int> hash {
            { QStringLiteral("Actions"), KIconLoader::Action },
            { QStringLiteral("Applications"), KIconLoader::Application },
            { QStringLiteral("Categories"), KIconLoader::Category },
            { QStringLiteral("Devices"), KIconLoader::Device },
            { QStringLiteral("Emblems"), KIconLoader::Emblem },
            { QStringLiteral("Emotes"), KIconLoader::Emote },
            { QStringLiteral("MimeTypes"), KIconLoader::MimeType },
            { QStringLiteral("Places"), KIconLoader::Place },
            { QStringLiteral("Status"), KIconLoader::StatusIcon },
        };
        auto value = hash.value(string, -1);
        return (KIconLoader::Context)value;
    }

    KIconLoader::Type parseType(const QString &string)
    {
        bool ok;
        auto v = (KIconLoader::Type)typeEnum().keyToValue(string.toLatin1(), &ok);
        Q_ASSERT(ok);
        return v;
    }

    /**
     * @returns list of all icon's fileinfo (first level only, selected types
     *          only)
     */
    QList<QFileInfo> allIcons()
    {
        QList<QFileInfo> icons;
        auto iconDir = QString("%1/%2").arg(themeDir).arg(path);
        QDirIterator it(iconDir);
        while (it.hasNext()) {
            it.next();
            auto suffix = it.fileInfo().suffix();
            if (suffix != "svg" && suffix != "svgz" && suffix != "png") {
                continue; // Probably not an icon.
            }
            icons << it.fileInfo();
        }
        return icons;
    }

    bool exists;
    QString themeDir;
    QString path;
    uint size;
    QString contextString;
    KIconLoader::Context context;
    KIconLoader::Type type;
};

// Declare so we can put them into the QTest data table.
Q_DECLARE_METATYPE(KIconLoader::Context)
Q_DECLARE_METATYPE(Dir*)

class ScalableTest : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    // NB: test_scalable_data leaks Dir*. Should this test grow more slots it may be wise to
    //     introduce a cleanup() to make sure the test doesn't OOM.

    void test_scalable_data()
    {
        for (auto dir : ICON_DIRS) {
            auto themeDir = PROJECT_SOURCE_DIR + QStringLiteral("/") + dir;

            QHash<KIconLoader::Context, QList<Dir *>> contextHash;
            QHash<KIconLoader::Context, QString> contextStringHash;

            KConfig config(themeDir + "/index.theme");
            auto directoryPaths = config.group("Icon Theme").readEntry("Directories", QString()).split(",");
            QVERIFY(!directoryPaths.isEmpty());
            for (auto directoryPath : directoryPaths) {
                auto dir = new Dir(config.group(directoryPath), themeDir);
                contextHash[dir->context].append(dir);
                contextStringHash[dir->context] = (dir->contextString);
            }

            QTest::addColumn<KIconLoader::Context>("context");
            QTest::addColumn<QList<Dir *>>("dirs");

            for (auto key : contextHash.keys()) {
                if (key != KIconLoader::Application) {
                    qDebug() << "Only testing Application context for now.";
                    continue;
                }
                // FIXME: go through qenum to stringify the bugger
                // Gets rid of the stupid second hash
                auto contextId = QString(QLatin1String(dir) + ":" + contextStringHash[key]).toLatin1();
                QTest::newRow(contextId) << key << contextHash[key];
            }
        }
    }

    void test_scalable()
    {
        QFETCH(KIconLoader::Context, context);
        QFETCH(QList<Dir *>, dirs);

        QList<Dir *> fixedDirs;
        QList<Dir *> scalableDirs;
        for (auto dir : dirs) {
            switch (dir->type) {
            case KIconLoader::Scalable:
                scalableDirs << dir;
                break;
            case KIconLoader::Fixed:
                fixedDirs << dir;
                break;
            case KIconLoader::Threshold:
                QVERIFY2(false, "Test does not support threshold icons right now.");
            }
        }

        // FIXME: context should be translated through qenum
        switch (context) {
        case KIconLoader::Application:
            // Treat this as a problem.
            QVERIFY2(!scalableDirs.empty(), "This icon context has no scalable directory at all!");
            break;
        default:
            qWarning() << "All context but Application are whitelisted from having a scalable directory.";
            return;
        }

        QStringList fixedIcons;
        for (auto dir : fixedDirs) {
            for (auto iconInfo : dir->allIcons()) {
                fixedIcons << iconInfo.completeBaseName();
            }
        }

        QHash<QString, QList<QFileInfo>> scalableIcons;
        for (auto dir : scalableDirs) {
            for (auto iconInfo : dir->allIcons()) {
                scalableIcons[iconInfo.completeBaseName()].append(iconInfo);
            }
        }

        QStringList notScalableIcons;
        for (auto fixed : fixedIcons) {
            if (scalableIcons.keys().contains(fixed)) {
                continue;
            }
            notScalableIcons << fixed;
        }

        // Assert that each icon has a scalable variant.
        if (notScalableIcons.empty()) {
            return;
        }
        notScalableIcons.removeDuplicates();
        QFAIL(QString("The following icons are not available in a scalable directory:\n  %1")
              .arg(notScalableIcons.join("\n  "))
              .toLatin1());
    }

    void test_scalableDuplicates_data()
    {
        test_scalable_data();
    }

    void test_scalableDuplicates()
    {
        QFETCH(QList<Dir *>, dirs);

        QList<Dir *> scalableDirs;
        for (auto dir : dirs) {
            switch (dir->type) {
            case KIconLoader::Scalable:
                scalableDirs << dir;
                break;
            case KIconLoader::Fixed:
                // Not of interest in this test.
                break;
            case KIconLoader::Threshold:
                QVERIFY2(false, "Test does not support threshold icons right now.");
            }
        }

        QHash<QString, QList<QFileInfo>> scalableIcons;
        for (auto dir : scalableDirs) {
            for (auto iconInfo : dir->allIcons()) {
                scalableIcons[iconInfo.completeBaseName()].append(iconInfo);
            }
        }

        QHash<QString, QList<QFileInfo>> duplicatedScalableIcons;
        for (auto icon: scalableIcons.keys()) {
            auto list = scalableIcons[icon];
            if (list.size() > 1) {
                duplicatedScalableIcons[icon] = list;
            }
        }

        // Assert that there is only one scalable version per icon name.
        // Otherwise apps/32/klipper.svg OR apps/48/klipper.svg may be used.
        if (!duplicatedScalableIcons.empty()) {
            QString msg;
            QTextStream stream(&msg);
            stream << "Duplicated scalable icons:" << endl;
            for (auto icon : duplicatedScalableIcons.keys()) {
                stream << QString("  %1:").arg(icon) << endl;
                for (auto info : duplicatedScalableIcons[icon]) {
                    stream << QString("    %1").arg(info.absoluteFilePath()) << endl;
                }
            }
            QFAIL(msg.toLatin1());
        }
    }
};

QTEST_GUILESS_MAIN(ScalableTest)

#include "scalabletest.moc"
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file math.hpp
 * \date January 2015
 * \author Jan Issac (jan.issac@gmail.com)
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 */

#ifndef FL__UTIL__MATH_HPP
#define FL__UTIL__MATH_HPP

#include <Eigen/Dense>

#include <cmath>
#include <vector>
#include <random>

#include <iostream>

namespace fl
{

/**
 * Euler-Mascheroni Constant
 * \ingroup math
 */
static constexpr double GAMMA =
        0.57721566490153286060651209008240243104215933593992;

/**
 * \brief Sigmoid function
 * \ingroup math
 */
constexpr double sigmoid(const double& x)
{
    return 1.0 / (1.0 + std::exp(-x));
}

/**
 * \brief log odd
 * \ingroup math
 */
constexpr double logit(const double& x)
{
    return std::log(x / (1.0 - x));
}

/**
 * \ingroup math
 *
 * Normalizes the values of input vector such that their sum is equal to the
 * specified \c sum. For instance, any convex combination requires that the
 * weights of the weighted sum sums up to 1.
 */
template <typename T>
inline std::vector<T> normalize(const std::vector<T>& input, T sum)
{
    T old_sum = 0;
    for(size_t i = 0; i < input.size(); i++)
    {
        old_sum += input[i];
    }
    T factor = sum/old_sum;

    std::vector<T> output(input.size());
    for(size_t i = 0; i < input.size(); i++)
    {
        output[i] = factor*input[i];
    }

    return output;
}

/**
 * \brief Incomplete upper gamma function for positive \c a and \c z
 * \ingroup math
 *
 * This is the unnormalized incomplete upper gamma function implementing the
 * continued fraction representation \cite press2007numerical .
 *
 * \f$ \Gamma(a, z) = \int\limits^\infty_z t^{a-1}e^{-t}dt \f$
 *
 * \return \f$ \Gamma(a, z) \f$
 */
inline double igamma(const double a, const double z)
{
    static constexpr double EPS = std::numeric_limits<double>::epsilon();
    static constexpr double FPMIN = std::numeric_limits<double>::min() / EPS;

    if (z <= 0.) return std::numeric_limits<double>::quiet_NaN();

    int i;
    double an, b, c, d, del, h;

    b = z + 1.0 - a;
    c = 1.0 / FPMIN;
    d = 1.0 / b;
    h = d;

    for (i = 1; ; i++)
    {
        an = -i * (i - a);
        b += 2.0;
        d = an * d + b;
        if (std::fabs(d) < FPMIN) d = FPMIN;
        c = b + an / c;
        if (std::fabs(c) < FPMIN) c = FPMIN;
        d = 1.0 / d;
        del = d * c;
        h *= del;

        if (std::fabs(del - 1.0) <= EPS) break;
    }

    return std::exp(-z + a * std::log(z)) * h;
}

/**
 * \brief This is a deterministic exponential integral approximation
 *        \cite barry2000approximation .
 * \ingroup math
 *
 *
 * The exponential integral \f$E_1(z)\f$ is a special case of the upper
 * incomplete gamma function
 *
 * \f$ \Gamma(a, z) = \int\limits^\infty_z t^{a-1}e^{-t}dt \f$
 *
 * for \f$a = 0\f$ the gamma function is known as the exponential integral
 *
 * \f$ \Gamma(0, z) = \int\limits^\infty_z t^{-1}e^{-t}dt = E_1(z)\f$
 *
 * \return \f$E_1(z) = \Gamma(0, z)\f$
 * \note For high accuracy please use igamma(0, z)
 */
inline double exponential_integral(double z)
{
    if (z < 10.) return igamma(0., z);

    static constexpr double G = std::exp(-fl::GAMMA);
    static constexpr double b = std::sqrt((2. * (1.-G)) / (G * (2. - G)));
    static constexpr double h_inf = ((1.-G) * (std::pow(G, 2.) - 6. * G + 12.))
                                     / (3. * G * std::pow((2. - G), 2.) * b);

    static constexpr double q_frac = 20. / 47.;
    static constexpr double q_expx = std::sqrt(31. / 26.);

    const double q = q_frac * std::pow(z, q_expx);
    const double h = 1. / (1. + z * std::sqrt(z)) + (h_inf * q) / (1. + q);

    double E1 = std::exp(-z) *
                std::log(1. + G/z - (1.-G) / std::pow(h + b*z, 2.));
    E1 /= (G + (1. - G) * std::exp(-z / (1. - G)));

    return E1;
}

/**
 * Inverse of the error function.
 * \ingroup math
 *
 * \tparam RealType Argument and result type
 *
 * \return evaluates the erfinv at \f$ x \in (-1; 1) \f$
 */
template <typename RealType> inline RealType erfinv(RealType x);

/**
 * Single precision implementation of erfinv according to
 * \cite giles2010approximating
 * \ingroup math
 *
 * \return evaluates the erfinv at \f$ x \in (-1; 1) \f$
 */
template <> inline float erfinv<float>(float x)
{
    float w, p;
    w = - std::log((1.0f-x)*(1.0f+x));
    if ( w < 5.000000f )
    {
        w = w - 2.500000f;
        p =  2.81022636e-08f;
        p =  3.43273939e-07f + p * w;
        p =  -3.5233877e-06f + p * w;
        p = -4.39150654e-06f + p * w;
        p =   0.00021858087f + p * w;
        p =  -0.00125372503f + p * w;
        p =  -0.00417768164f + p * w;
        p =     0.246640727f + p * w;
        p =      1.50140941f + p * w;
    }
    else
    {
        w = std::sqrt(w) - 3.000000f;
        p = -0.000200214257f;
        p =  0.000100950558f + p * w;
        p =   0.00134934322f + p * w;
        p =  -0.00367342844f + p * w;
        p =   0.00573950773f + p * w;
        p =   -0.0076224613f + p * w;
        p =   0.00943887047f + p * w;
        p =      1.00167406f + p * w;
        p =      2.83297682f + p * w;
    }

    return p*x;
}

/**
 * Single precision implementation of erfinv according to
 * \cite giles2010approximating
 *
 * \ingroup math
 *
 * \return evaluates the erfinv at \f$ x \in (-1; 1) \f$
 */
template <> inline  double erfinv<double>(double x)
{
    double w, p;

    w = - std::log((1.0-x)*(1.0+x));

    if ( w < 6.250000 )
    {
        w = w - 3.125000;
        p =  -3.6444120640178196996e-21;
        p =   -1.685059138182016589e-19 + p * w;
        p =   1.2858480715256400167e-18 + p * w;
        p =    1.115787767802518096e-17 + p * w;
        p =   -1.333171662854620906e-16 + p * w;
        p =   2.0972767875968561637e-17 + p * w;
        p =   6.6376381343583238325e-15 + p * w;
        p =  -4.0545662729752068639e-14 + p * w;
        p =  -8.1519341976054721522e-14 + p * w;
        p =   2.6335093153082322977e-12 + p * w;
        p =  -1.2975133253453532498e-11 + p * w;
        p =  -5.4154120542946279317e-11 + p * w;
        p =    1.051212273321532285e-09 + p * w;
        p =  -4.1126339803469836976e-09 + p * w;
        p =  -2.9070369957882005086e-08 + p * w;
        p =   4.2347877827932403518e-07 + p * w;
        p =  -1.3654692000834678645e-06 + p * w;
        p =  -1.3882523362786468719e-05 + p * w;
        p =    0.0001867342080340571352 + p * w;
        p =  -0.00074070253416626697512 + p * w;
        p =   -0.0060336708714301490533 + p * w;
        p =      0.24015818242558961693 + p * w;
        p =       1.6536545626831027356 + p * w;
    }
    else if ( w < 16.000000 )
    {
        w = std::sqrt(w) - 3.250000;
        p =   2.2137376921775787049e-09;
        p =   9.0756561938885390979e-08 + p * w;
        p =  -2.7517406297064545428e-07 + p * w;
        p =   1.8239629214389227755e-08 + p * w;
        p =   1.5027403968909827627e-06 + p * w;
        p =   -4.013867526981545969e-06 + p * w;
        p =   2.9234449089955446044e-06 + p * w;
        p =   1.2475304481671778723e-05 + p * w;
        p =  -4.7318229009055733981e-05 + p * w;
        p =   6.8284851459573175448e-05 + p * w;
        p =   2.4031110387097893999e-05 + p * w;
        p =   -0.0003550375203628474796 + p * w;
        p =   0.00095328937973738049703 + p * w;
        p =   -0.0016882755560235047313 + p * w;
        p =    0.0024914420961078508066 + p * w;
        p =   -0.0037512085075692412107 + p * w;
        p =     0.005370914553590063617 + p * w;
        p =       1.0052589676941592334 + p * w;
        p =       3.0838856104922207635 + p * w;
    }
    else
    {
        w = std::sqrt(w) - 5.000000;
        p =  -2.7109920616438573243e-11;
        p =  -2.5556418169965252055e-10 + p * w;
        p =   1.5076572693500548083e-09 + p * w;
        p =  -3.7894654401267369937e-09 + p * w;
        p =   7.6157012080783393804e-09 + p * w;
        p =  -1.4960026627149240478e-08 + p * w;
        p =   2.9147953450901080826e-08 + p * w;
        p =  -6.7711997758452339498e-08 + p * w;
        p =   2.2900482228026654717e-07 + p * w;
        p =  -9.9298272942317002539e-07 + p * w;
        p =   4.5260625972231537039e-06 + p * w;
        p =  -1.9681778105531670567e-05 + p * w;
        p =   7.5995277030017761139e-05 + p * w;
        p =  -0.00021503011930044477347 + p * w;
        p =  -0.00013871931833623122026 + p * w;
        p =       1.0103004648645343977 + p * w;
        p =       4.8499064014085844221 + p * w;
    }

    return p*x;
}

/**
 * \brief Constructs the QuaternionMatrix for the specified quaternion vetcor
 * \ingroup math
 *
 * \param q_xyzw  Quaternion vector
 *
 * \return Matrix representation of the quaternion vector
 */
inline Eigen::Matrix<double, 4, 3> QuaternionMatrix(
        const Eigen::Matrix<double, 4, 1>& q_xyzw)
{
    Eigen::Matrix<double, 4, 3> Q;
    Q <<	q_xyzw(3), q_xyzw(2), -q_xyzw(1),
            -q_xyzw(2), q_xyzw(3), q_xyzw(0),
            q_xyzw(1), -q_xyzw(0), q_xyzw(3),
            -q_xyzw(0), -q_xyzw(1), -q_xyzw(2);

    return 0.5*Q;
}

}

#endif
<commit_msg>distributed all math function to the math sub categories within math/<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file math.hpp
 * \date January 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__UTIL__MATH_HPP
#define FL__UTIL__MATH_HPP

#include "math/general_functions.hpp"
#include "math/special_functions.hpp"
#include "math/linear_algebra.hpp"

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Implementations of vector/matrix scalar operations.
 */

#pragma once

//Include the implementations
#include "etl/impl/std/scalar_op.hpp"
#include "etl/impl/blas/scalar_op.hpp"

namespace etl {

namespace detail {

/*!
 * \brief Select the scalar implementation for an expression of type A
 *
 * The local context is not taken into account
 *
 * \tparam A The type of expression
 * \return The implementation to use
 */
template <typename A>
cpp14_constexpr scalar_impl select_default_scalar_impl() {
    if (all_floating<A>::value) {
        if (is_cblas_enabled) {
            return scalar_impl::BLAS;
        } else {
            return scalar_impl::STD;
        }
    }

    return scalar_impl::STD;
}

/*!
 * \brief Select the scalar implementation for an expression of type A
 * \tparam A The type of expression
 * \return The implementation to use
 */
template <typename A>
scalar_impl select_scalar_impl() {
    if (local_context().scalar_selector.forced) {
        auto forced = local_context().scalar_selector.impl;

        switch (forced) {
            //BLAS cannot always be used
            case scalar_impl::BLAS:
                if (!is_cblas_enabled || !all_floating<A>::value) {
                    std::cerr << "Forced selection to BLAS scalar implementation, but not possible for this expression" << std::endl;
                    return select_default_scalar_impl<A>();
                }

                return forced;

            //In other cases, simply use the forced impl
            default:
                return forced;
        }
    }

    return select_default_scalar_impl<A>();
}

/*!
 * \brief Functor to add a scalar to each element of an expression
 */
struct scalar_add {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_add(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_add(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to remove a scalar from each element of an expression
 */
struct scalar_sub {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_sub(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_sub(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to multiply each element of an expression by a scalar
 */
struct scalar_mul {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_mul(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_mul(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to divide each element of an expression by a scalar
 */
struct scalar_div {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_div(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_div(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to modulo each element of an expression by a scalar
 */
struct scalar_mod {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        etl::impl::standard::scalar_mod(lhs, rhs);
    }
};

} //end of namespace detail

} //end of namespace etl
<commit_msg>Better selection<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Implementations of vector/matrix scalar operations.
 */

#pragma once

//Include the implementations
#include "etl/impl/std/scalar_op.hpp"
#include "etl/impl/blas/scalar_op.hpp"

namespace etl {

namespace detail {

/*!
 * \brief Select the scalar implementation for an expression of type A
 *
 * The local context is not taken into account
 *
 * \tparam A The type of expression
 * \return The implementation to use
 */
template <typename A, bool Simple>
cpp14_constexpr scalar_impl select_default_scalar_impl() {
    if (all_floating<A>::value) {
        if (is_cblas_enabled && !Simple) {
            return scalar_impl::BLAS;
        } else {
            return scalar_impl::STD;
        }
    }

    return scalar_impl::STD;
}

/*!
 * \brief Select the scalar implementation for an expression of type A
 * \tparam A The type of expression
 * \return The implementation to use
 */
template <typename A, bool Simple>
scalar_impl select_scalar_impl() {
    if (local_context().scalar_selector.forced) {
        auto forced = local_context().scalar_selector.impl;

        switch (forced) {
            //BLAS cannot always be used
            case scalar_impl::BLAS:
                if (!is_cblas_enabled || !all_floating<A>::value) {
                    std::cerr << "Forced selection to BLAS scalar implementation, but not possible for this expression" << std::endl;
                    return select_default_scalar_impl<A, Simple>();
                }

                return forced;

            //In other cases, simply use the forced impl
            default:
                return forced;
        }
    }

    return select_default_scalar_impl<A, Simple>();
}

/*!
 * \brief Functor to add a scalar to each element of an expression
 */
struct scalar_add {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T, true>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_add(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_add(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to remove a scalar from each element of an expression
 */
struct scalar_sub {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T, true>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_sub(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_sub(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to multiply each element of an expression by a scalar
 */
struct scalar_mul {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T, false>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_mul(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_mul(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to divide each element of an expression by a scalar
 */
struct scalar_div {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        auto impl = select_scalar_impl<T, false>();

        if (impl == scalar_impl::BLAS) {
            return etl::impl::blas::scalar_div(lhs, rhs);
        } else {
            return etl::impl::standard::scalar_div(lhs, rhs);
        }
    }
};

/*!
 * \brief Functor to modulo each element of an expression by a scalar
 */
struct scalar_mod {
    /*!
     * \brief Apply the operation on the expression lhs and the scalar rhs
     * \param lhs The expression
     * \param rhs The scalar
     */
    template <typename T>
    static void apply(T&& lhs, value_t<T> rhs) {
        etl::impl::standard::scalar_mod(lhs, rhs);
    }
};

} //end of namespace detail

} //end of namespace etl
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_MULTIPLICATION_HPP
#define ETL_MULTIPLICATION_HPP

#include <algorithm>

namespace etl {

namespace detail {

template<typename A, typename B, typename C, cpp::disable_if_all_u<etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast> = cpp::detail::dummy>
void check_mmul_sizes(const A& a, const B& b, C& c){
    cpp_assert(
            dim<1>(a) == dim<0>(b)          //interior dimensions
        &&  dim<0>(a) == dim<0>(c)          //exterior dimension 1
        &&  dim<1>(b) == dim<1>(c),         //exterior dimension 2
        "Invalid sizes for multiplication");
    cpp_unused(a);
    cpp_unused(b);
    cpp_unused(c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast> = cpp::detail::dummy>
void check_mmul_sizes(const A&, const B&, C&){
    static_assert(
            etl_traits<A>::template dim<1>() == etl_traits<B>::template dim<0>()          //interior dimensions
        &&  etl_traits<A>::template dim<0>() == etl_traits<C>::template dim<0>()          //exterior dimension 1
        &&  etl_traits<B>::template dim<1>() == etl_traits<C>::template dim<1>(),         //exterior dimension 2
        "Invalid sizes for multiplication");
}

} //end of namespace detail

template<typename A, typename B, typename C>
static C& mmul(const A& a, const B& b, C& c){
    static_assert(is_etl_expr<A>::value && is_etl_expr<B>::value && is_etl_expr<C>::value, "Matrix multiplication only supported for ETL expressions");
    static_assert(etl_traits<A>::dimensions() == 2 && etl_traits<B>::dimensions() == 2 && etl_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
    detail::check_mmul_sizes(a,b,c);

    c = 0;

    for(std::size_t i = 0; i < rows(a); i++){
        for(std::size_t j = 0; j < columns(b); j++){
            for(std::size_t k = 0; k < columns(a); k++){
                c(i,j) += a(i,k) * b(k,j);
            }
        }
    }

    return c;
}

inline std::size_t nextPowerOfTwo(std::size_t n) {
    return std::pow(2, static_cast<std::size_t>(std::ceil(std::log2(n))));
}

template<typename A, typename B, typename C>
static void strassen_mmul_r(const A& a, const B& b, C& c){
    using type = typename A::value_type;

    auto n = dim<0>(a);

    //1x1 matrix mul
    if (n == 1) {
        c(0,0) = a(0,0) * b(0,0);
    } else {
        auto new_n = n / 2;

        etl::dyn_matrix<type> a11(new_n, new_n);
        etl::dyn_matrix<type> a12(new_n, new_n);
        etl::dyn_matrix<type> a21(new_n, new_n);
        etl::dyn_matrix<type> a22(new_n, new_n);

        etl::dyn_matrix<type> b11(new_n, new_n);
        etl::dyn_matrix<type> b12(new_n, new_n);
        etl::dyn_matrix<type> b21(new_n, new_n);
        etl::dyn_matrix<type> b22(new_n, new_n);

        etl::dyn_matrix<type> p1(new_n, new_n);
        etl::dyn_matrix<type> p2(new_n, new_n);
        etl::dyn_matrix<type> p3(new_n, new_n);
        etl::dyn_matrix<type> p4(new_n, new_n);
        etl::dyn_matrix<type> p5(new_n, new_n);

        for (std::size_t i = 0; i < new_n; i++) {
            for (std::size_t j = 0; j < new_n; j++) {
                a11(i,j) = a(i,j);
                a12(i,j) = a(i,j + new_n);
                a21(i,j) = a(i + new_n,j);
                a22(i,j) = a(i + new_n,j + new_n);

                b11(i,j) = b(i,j);
                b12(i,j) = b(i,j + new_n);
                b21(i,j) = b(i + new_n,j);
                b22(i,j) = b(i + new_n,j + new_n);
            }
        }

        strassen_mmul_r(a11 + a22, b11 + b22, p1);
        strassen_mmul_r(a12 - a22, b21 + b22, p2);
        strassen_mmul_r(a22, b21 - b11, p4);
        strassen_mmul_r(a11 + a12, b22, p5);

        auto c11 = p1 + p4 + p2 - p5;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i,j) = c11(i,j);
            }
        }

        strassen_mmul_r(a11, b12 - b22, p3);

        auto c12 = p3 + p5;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i,j + new_n) = c12(i,j);
            }
        }

        strassen_mmul_r(a21 + a22, b11, p2);
        strassen_mmul_r(a21 - a11, b11 + b12, p5);

        auto c21 = p2 + p4;
        auto c22 = p1 + p3 + p5 - p2;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i + new_n,j) = c21(i,j);
                c(i + new_n,j + new_n) = c22(i,j);
            }
        }
    }
}

template<typename A, typename B, typename C>
static C& strassen_mmul(const A& a, const B& b, C& c){
    static_assert(is_etl_expr<A>::value && is_etl_expr<B>::value && is_etl_expr<C>::value, "Matrix multiplication only supported for ETL expressions");
    static_assert(etl_traits<A>::dimensions() == 2 && etl_traits<B>::dimensions() == 2 && etl_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
    detail::check_mmul_sizes(a,b,c);

    c = 0;

    //For now, assume matrices are of size 2^nx2^n

    auto n = std::max(dim<0>(a), std::max(dim<1>(a), dim<1>(b)));
    auto m = nextPowerOfTwo(n);

    if(dim<0>(a) == m && dim<0>(b) == m && dim<1>(a) == m && dim<1>(b) == m){
        strassen_mmul_r(a, b, c);
    } else {
        using type = typename A::value_type;

        etl::dyn_matrix<type> a_prep(m, m, static_cast<type>(0));
        etl::dyn_matrix<type> b_prep(m, m, static_cast<type>(0));
        etl::dyn_matrix<type> c_prep(m, m, static_cast<type>(0));

        for(std::size_t i=0; i< dim<0>(a); i++) {
            for (std::size_t j=0; j<dim<1>(a); j++) {
                a_prep(i,j) = a(i,j);
            }
        }

        for(std::size_t i=0; i< dim<0>(b); i++) {
            for (std::size_t j=0; j<dim<1>(b); j++) {
                b_prep(i,j) = b(i,j);
            }
        }

        strassen_mmul_r(a_prep, b_prep, c_prep);

        for(std::size_t i=0; i< dim<0>(c); i++) {
            for (std::size_t j=0; j<dim<1>(c); j++) {
                c(i,j) = c_prep(i,j);
            }
        }
    }

    return c;
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape<1, etl_traits<B>::template dim<0>()>(a), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape<etl_traits<A>::template dim<1>(),1>(b), c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2,
    cpp::not_u<etl_traits<A>::is_fast>::value
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape(a, 1, dim<0>(b)), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1,
    cpp::not_u<etl_traits<B>::is_fast>::value
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape(b, dim<1>(a), 1), c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2,
    etl_traits<A>::is_fast
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape<1, etl_traits<B>::template dim<0>()>(a), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1,
    etl_traits<B>::is_fast
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape<etl_traits<A>::template dim<1>(),1>(b), c);
}

} //end of namespace etl

#endif
<commit_msg>Do n==2 without allocations<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_MULTIPLICATION_HPP
#define ETL_MULTIPLICATION_HPP

#include <algorithm>

namespace etl {

namespace detail {

template<typename A, typename B, typename C, cpp::disable_if_all_u<etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast> = cpp::detail::dummy>
void check_mmul_sizes(const A& a, const B& b, C& c){
    cpp_assert(
            dim<1>(a) == dim<0>(b)          //interior dimensions
        &&  dim<0>(a) == dim<0>(c)          //exterior dimension 1
        &&  dim<1>(b) == dim<1>(c),         //exterior dimension 2
        "Invalid sizes for multiplication");
    cpp_unused(a);
    cpp_unused(b);
    cpp_unused(c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast> = cpp::detail::dummy>
void check_mmul_sizes(const A&, const B&, C&){
    static_assert(
            etl_traits<A>::template dim<1>() == etl_traits<B>::template dim<0>()          //interior dimensions
        &&  etl_traits<A>::template dim<0>() == etl_traits<C>::template dim<0>()          //exterior dimension 1
        &&  etl_traits<B>::template dim<1>() == etl_traits<C>::template dim<1>(),         //exterior dimension 2
        "Invalid sizes for multiplication");
}

} //end of namespace detail

template<typename A, typename B, typename C>
static C& mmul(const A& a, const B& b, C& c){
    static_assert(is_etl_expr<A>::value && is_etl_expr<B>::value && is_etl_expr<C>::value, "Matrix multiplication only supported for ETL expressions");
    static_assert(etl_traits<A>::dimensions() == 2 && etl_traits<B>::dimensions() == 2 && etl_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
    detail::check_mmul_sizes(a,b,c);

    c = 0;

    for(std::size_t i = 0; i < rows(a); i++){
        for(std::size_t j = 0; j < columns(b); j++){
            for(std::size_t k = 0; k < columns(a); k++){
                c(i,j) += a(i,k) * b(k,j);
            }
        }
    }

    return c;
}

inline std::size_t nextPowerOfTwo(std::size_t n) {
    return std::pow(2, static_cast<std::size_t>(std::ceil(std::log2(n))));
}

template<typename A, typename B, typename C>
static void strassen_mmul_r(const A& a, const B& b, C& c){
    using type = typename A::value_type;

    auto n = dim<0>(a);

    //1x1 matrix mul
    if (n == 1) {
        c(0,0) = a(0,0) * b(0,0);
    } else if(n == 2){
        auto a11 = a(0,0);
        auto a12 = a(0,1);
        auto a21 = a(1,0);
        auto a22 = a(1,1);

        auto b11 = b(0,0);
        auto b12 = b(0,1);
        auto b21 = b(1,0);
        auto b22 = b(1,1);

        auto p1 = (a11 + a22) * (b11 + b22);
        auto p2 = (a12 - a22) * (b21 + b22);
        auto p3 = a11 * (b12 - b22);
        auto p4 = a22 * (b21 - b11);
        auto p5 = (a11 + a12) * b22;
        auto p6 = (a21 + a22) * b11;
        auto p7 = (a21 - a11) * (b11 + b12);

        c(0,0) = p1 + p4 + p2 - p5;
        c(0,1) = p3 + p5;
        c(1,0) = p6 + p4;
        c(1,1) = p1 + p3 + p7 - p6;
    } else {
        auto new_n = n / 2;

        etl::dyn_matrix<type> a11(new_n, new_n);
        etl::dyn_matrix<type> a12(new_n, new_n);
        etl::dyn_matrix<type> a21(new_n, new_n);
        etl::dyn_matrix<type> a22(new_n, new_n);

        etl::dyn_matrix<type> b11(new_n, new_n);
        etl::dyn_matrix<type> b12(new_n, new_n);
        etl::dyn_matrix<type> b21(new_n, new_n);
        etl::dyn_matrix<type> b22(new_n, new_n);

        etl::dyn_matrix<type> p1(new_n, new_n);
        etl::dyn_matrix<type> p2(new_n, new_n);
        etl::dyn_matrix<type> p3(new_n, new_n);
        etl::dyn_matrix<type> p4(new_n, new_n);
        etl::dyn_matrix<type> p5(new_n, new_n);

        for (std::size_t i = 0; i < new_n; i++) {
            for (std::size_t j = 0; j < new_n; j++) {
                a11(i,j) = a(i,j);
                a12(i,j) = a(i,j + new_n);
                a21(i,j) = a(i + new_n,j);
                a22(i,j) = a(i + new_n,j + new_n);

                b11(i,j) = b(i,j);
                b12(i,j) = b(i,j + new_n);
                b21(i,j) = b(i + new_n,j);
                b22(i,j) = b(i + new_n,j + new_n);
            }
        }

        strassen_mmul_r(a11 + a22, b11 + b22, p1);
        strassen_mmul_r(a12 - a22, b21 + b22, p2);
        strassen_mmul_r(a22, b21 - b11, p4);
        strassen_mmul_r(a11 + a12, b22, p5);

        auto c11 = p1 + p4 + p2 - p5;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i,j) = c11(i,j);
            }
        }

        strassen_mmul_r(a11, b12 - b22, p3);

        auto c12 = p3 + p5;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i,j + new_n) = c12(i,j);
            }
        }

        strassen_mmul_r(a21 + a22, b11, p2);
        strassen_mmul_r(a21 - a11, b11 + b12, p5);

        auto c21 = p2 + p4;
        auto c22 = p1 + p3 + p5 - p2;

        for (std::size_t i = 0; i < new_n ; i++) {
            for (std::size_t j = 0 ; j < new_n ; j++) {
                c(i + new_n,j) = c21(i,j);
                c(i + new_n,j + new_n) = c22(i,j);
            }
        }
    }
}

template<typename A, typename B, typename C>
static C& strassen_mmul(const A& a, const B& b, C& c){
    static_assert(is_etl_expr<A>::value && is_etl_expr<B>::value && is_etl_expr<C>::value, "Matrix multiplication only supported for ETL expressions");
    static_assert(etl_traits<A>::dimensions() == 2 && etl_traits<B>::dimensions() == 2 && etl_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
    detail::check_mmul_sizes(a,b,c);

    c = 0;

    //For now, assume matrices are of size 2^nx2^n

    auto n = std::max(dim<0>(a), std::max(dim<1>(a), dim<1>(b)));
    auto m = nextPowerOfTwo(n);

    if(dim<0>(a) == m && dim<0>(b) == m && dim<1>(a) == m && dim<1>(b) == m){
        strassen_mmul_r(a, b, c);
    } else {
        using type = typename A::value_type;

        etl::dyn_matrix<type> a_prep(m, m, static_cast<type>(0));
        etl::dyn_matrix<type> b_prep(m, m, static_cast<type>(0));
        etl::dyn_matrix<type> c_prep(m, m, static_cast<type>(0));

        for(std::size_t i=0; i< dim<0>(a); i++) {
            for (std::size_t j=0; j<dim<1>(a); j++) {
                a_prep(i,j) = a(i,j);
            }
        }

        for(std::size_t i=0; i< dim<0>(b); i++) {
            for (std::size_t j=0; j<dim<1>(b); j++) {
                b_prep(i,j) = b(i,j);
            }
        }

        strassen_mmul_r(a_prep, b_prep, c_prep);

        for(std::size_t i=0; i< dim<0>(c); i++) {
            for (std::size_t j=0; j<dim<1>(c); j++) {
                c(i,j) = c_prep(i,j);
            }
        }
    }

    return c;
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape<1, etl_traits<B>::template dim<0>()>(a), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    etl_traits<A>::is_fast, etl_traits<B>::is_fast, etl_traits<C>::is_fast,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape<etl_traits<A>::template dim<1>(),1>(b), c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2,
    cpp::not_u<etl_traits<A>::is_fast>::value
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape(a, 1, dim<0>(b)), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1,
    cpp::not_u<etl_traits<B>::is_fast>::value
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape(b, dim<1>(a), 1), c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 1, etl_traits<B>::dimensions() == 2,
    etl_traits<A>::is_fast
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(reshape<1, etl_traits<B>::template dim<0>()>(a), b, c);
}

template<typename A, typename B, typename C, cpp::enable_if_all_u<
    cpp::or_u<!etl_traits<A>::is_fast, !etl_traits<B>::is_fast, !etl_traits<C>::is_fast>::value,
    etl_traits<A>::dimensions() == 2, etl_traits<B>::dimensions() == 1,
    etl_traits<B>::is_fast
> = cpp::detail::dummy>
static C& auto_vmmul(const A& a, const B& b, C& c){
    return mmul(a, reshape<etl_traits<A>::template dim<1>(),1>(b), c);
}

} //end of namespace etl

#endif
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core 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
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_NODE_HH
# define HPP_CORE_NODE_HH

# include <hpp/pinocchio/fwd.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>

namespace hpp {
  namespace core {
    /// \addtogroup roadmap
    /// \{

    /// Node of a roadmap
    ///
    /// Stores a configuration.
    class HPP_CORE_DLLAPI Node {
    public:
      typedef std::list <EdgePtr_t> Edges_t;
      /// Constructor
      /// \param configuration configuration stored in the new node
      /// \note A new connected component is created. For consistency, the
      ///       new node is not registered in the connected component.
      Node (const ConfigurationPtr_t& configuration);
      /// Constructor
      /// \param configuration configuration stored in the new node
      /// \param connectedComponent connected component the node belongs to.
      Node (const ConfigurationPtr_t& configuration,
	    ConnectedComponentPtr_t connectedComponent);
      void addOutEdge (EdgePtr_t edge);
      void addInEdge (EdgePtr_t edge);
      /// Store the connected component the node belongs to
      void connectedComponent (const ConnectedComponentPtr_t& cc);
      ConnectedComponentPtr_t connectedComponent () const;
      /// Access to outEdges
      const Edges_t& outEdges () const;
      /// Access to inEdges
      const Edges_t& inEdges () const;
      /// Check whether otherNode is an out-neighbor of this node.
      /// Node B is an out-neighbor of node A if node A has an outgoing edge
      /// going to B.
      bool isOutNeighbor (const NodePtr_t& n) const;
      /// Check whether otherNode is an in-neighbor of this node.
      /// Node B is an in-neighbor of node A if node A has an ingoing edge
      /// going to B.
      bool isInNeighbor (const NodePtr_t& n) const;

      ConfigurationPtr_t configuration () const;
      /// Print node in a stream
      std::ostream& print (std::ostream& os) const;
    private:
      ConfigurationPtr_t configuration_;
      Edges_t outEdges_;
      Edges_t inEdges_;
      ConnectedComponentPtr_t connectedComponent_;
    }; // class Node
    std::ostream& operator<< (std::ostream& os, const Node& n);
    /// \}
  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_NODE_HH
<commit_msg>Add virtual destructor to Node<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core 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
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_NODE_HH
# define HPP_CORE_NODE_HH

# include <hpp/pinocchio/fwd.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>

namespace hpp {
  namespace core {
    /// \addtogroup roadmap
    /// \{

    /// Node of a roadmap
    ///
    /// Stores a configuration.
    class HPP_CORE_DLLAPI Node {
    public:
      typedef std::list <EdgePtr_t> Edges_t;
      /// Constructor
      /// \param configuration configuration stored in the new node
      /// \note A new connected component is created. For consistency, the
      ///       new node is not registered in the connected component.
      Node (const ConfigurationPtr_t& configuration);
      /// Constructor
      /// \param configuration configuration stored in the new node
      /// \param connectedComponent connected component the node belongs to.
      Node (const ConfigurationPtr_t& configuration,
	    ConnectedComponentPtr_t connectedComponent);
      void addOutEdge (EdgePtr_t edge);
      void addInEdge (EdgePtr_t edge);
      /// Store the connected component the node belongs to
      void connectedComponent (const ConnectedComponentPtr_t& cc);
      ConnectedComponentPtr_t connectedComponent () const;
      /// Access to outEdges
      const Edges_t& outEdges () const;
      /// Access to inEdges
      const Edges_t& inEdges () const;
      /// Check whether otherNode is an out-neighbor of this node.
      /// Node B is an out-neighbor of node A if node A has an outgoing edge
      /// going to B.
      bool isOutNeighbor (const NodePtr_t& n) const;
      /// Check whether otherNode is an in-neighbor of this node.
      /// Node B is an in-neighbor of node A if node A has an ingoing edge
      /// going to B.
      bool isInNeighbor (const NodePtr_t& n) const;

      ConfigurationPtr_t configuration () const;
      /// Print node in a stream
      std::ostream& print (std::ostream& os) const;

      virtual ~Node () {};
    private:
      ConfigurationPtr_t configuration_;
      Edges_t outEdges_;
      Edges_t inEdges_;
      ConnectedComponentPtr_t connectedComponent_;
    }; // class Node
    std::ostream& operator<< (std::ostream& os, const Node& n);
    /// \}
  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_NODE_HH
<|endoftext|>


<commit_before>//===- RustWrapper.cpp - Rust wrapper for core functions --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines alternate interfaces to core functions that are more
// readily callable by Rust's FFI.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Host.h"
#include "llvm-c/Core.h"
#include "llvm-c/BitReader.h"
#include "llvm-c/Object.h"
#include <cstdlib>

using namespace llvm;

static const char *LLVMRustError;

extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
  LLVMMemoryBufferRef MemBuf = NULL;
  LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf,
    const_cast<char **>(&LLVMRustError));
  return MemBuf;
}

extern "C" const char *LLVMRustGetLastError(void) {
  return LLVMRustError;
}

extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);

extern "C" bool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src) {
  static std::string err;

  // For some strange reason, unwrap() doesn't work here. "No matching
  // function" error.
  Module *DM = reinterpret_cast<Module *>(Dest);
  Module *SM = reinterpret_cast<Module *>(Src);
  if (Linker::LinkModules(DM, SM, &err)) {
    LLVMRustError = err.c_str();
    return false;
  }
  return true;
}

extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
                                        LLVMModuleRef M,
                                        const char *triple,
                                        const char *path,
                                        TargetMachine::CodeGenFileType FileType,
                                        CodeGenOpt::Level OptLevel) {

  // Set compilation options.
  llvm::NoFramePointerElim = true;

  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();
  std::string Err;
  const Target *TheTarget = TargetRegistry::lookupTarget(triple, Err);
  std::string FeaturesStr;
  std::string Trip(triple);
  std::string CPUStr = llvm::sys::getHostCPUName();
  TargetMachine *Target =
    TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr, Reloc::PIC_);
  bool NoVerify = false;
  PassManager *PM = unwrap<PassManager>(PMR);
  std::string ErrorInfo;
  raw_fd_ostream OS(path, ErrorInfo,
                    raw_fd_ostream::F_Binary);
  formatted_raw_ostream FOS(OS);

  bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, OptLevel,
                                         NoVerify);
  assert(!foo);
  (void)foo;
  PM->run(*unwrap(M));
  delete Target;
}

extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
  LLVMModuleRef M;
  return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
         ? NULL : M;
}

extern "C" const char *LLVMRustGetHostTriple(void)
{
  static std::string str = llvm::sys::getHostTriple();
  return str.c_str();
}

extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
                                              LLVMBool SignExtend) {
  return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend);
}

extern bool llvm::TimePassesIsEnabled;
extern "C" void LLVMRustEnableTimePasses() {
  TimePassesIsEnabled = true;
}

extern "C" void LLVMRustPrintPassTimings() {
  raw_fd_ostream OS (2, false); // stderr.
  TimerGroup::printAll(OS);
}
<commit_msg>Update LinkModules invocation to use new prototype<commit_after>//===- RustWrapper.cpp - Rust wrapper for core functions --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines alternate interfaces to core functions that are more
// readily callable by Rust's FFI.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Host.h"
#include "llvm-c/Core.h"
#include "llvm-c/BitReader.h"
#include "llvm-c/Object.h"
#include <cstdlib>

using namespace llvm;

static const char *LLVMRustError;

extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
  LLVMMemoryBufferRef MemBuf = NULL;
  LLVMCreateMemoryBufferWithContentsOfFile(Path, &MemBuf,
    const_cast<char **>(&LLVMRustError));
  return MemBuf;
}

extern "C" const char *LLVMRustGetLastError(void) {
  return LLVMRustError;
}

extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);

extern "C" bool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src) {
  static std::string err;

  // For some strange reason, unwrap() doesn't work here. "No matching
  // function" error.
  Module *DM = reinterpret_cast<Module *>(Dest);
  Module *SM = reinterpret_cast<Module *>(Src);
  if (Linker::LinkModules(DM, SM, Linker::DestroySource, &err)) {
    LLVMRustError = err.c_str();
    return false;
  }
  return true;
}

extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
                                        LLVMModuleRef M,
                                        const char *triple,
                                        const char *path,
                                        TargetMachine::CodeGenFileType FileType,
                                        CodeGenOpt::Level OptLevel) {

  // Set compilation options.
  llvm::NoFramePointerElim = true;

  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();
  std::string Err;
  const Target *TheTarget = TargetRegistry::lookupTarget(triple, Err);
  std::string FeaturesStr;
  std::string Trip(triple);
  std::string CPUStr = llvm::sys::getHostCPUName();
  TargetMachine *Target =
    TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr, Reloc::PIC_);
  bool NoVerify = false;
  PassManager *PM = unwrap<PassManager>(PMR);
  std::string ErrorInfo;
  raw_fd_ostream OS(path, ErrorInfo,
                    raw_fd_ostream::F_Binary);
  formatted_raw_ostream FOS(OS);

  bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, OptLevel,
                                         NoVerify);
  assert(!foo);
  (void)foo;
  PM->run(*unwrap(M));
  delete Target;
}

extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
  LLVMModuleRef M;
  return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
         ? NULL : M;
}

extern "C" const char *LLVMRustGetHostTriple(void)
{
  static std::string str = llvm::sys::getHostTriple();
  return str.c_str();
}

extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
                                              LLVMBool SignExtend) {
  return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend);
}

extern bool llvm::TimePassesIsEnabled;
extern "C" void LLVMRustEnableTimePasses() {
  TimePassesIsEnabled = true;
}

extern "C" void LLVMRustPrintPassTimings() {
  raw_fd_ostream OS (2, false); // stderr.
  TimerGroup::printAll(OS);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef LIBPORT_UTIME_HH
# define LIBPORT_UTIME_HH

# include <boost/date_time/posix_time/posix_time.hpp>

# include <libport/export.hh>
# include <libport/sys/time.h>
# include <libport/ufloat.hh>

namespace libport
{
  /// Microseconds.
  typedef long long utime_t;

  /// Convert from seconds to utime_t.
  template <typename Unit>
  utime_t seconds_to_utime(Unit seconds);

  /// From timeval to utime.
  utime_t timeval_to_utime(const timeval& t);

  /// Return elapsed time from an arbitrary basis in microseconds.
  LIBPORT_API utime_t utime();

  /// Return the arbitrary basis
  LIBPORT_API const boost::posix_time::ptime& utime_reference();

  /// Set the arbitrary basis
  void utime_reference_set(const boost::posix_time::ptime& ref);

  /// Convert from microseconds to timeval.
  timeval utime_to_timeval(utime_t t);

}

# include <libport/utime.hxx>

#endif // !LIBPORT_UTIME_HH
<commit_msg>Put libport::utime_reference_set in the API.<commit_after>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef LIBPORT_UTIME_HH
# define LIBPORT_UTIME_HH

# include <boost/date_time/posix_time/posix_time.hpp>

# include <libport/export.hh>
# include <libport/sys/time.h>
# include <libport/ufloat.hh>

namespace libport
{
  /// Microseconds.
  typedef long long utime_t;

  /// Convert from seconds to utime_t.
  template <typename Unit>
  utime_t seconds_to_utime(Unit seconds);

  /// From timeval to utime.
  utime_t timeval_to_utime(const timeval& t);

  /// Return elapsed time from an arbitrary basis in microseconds.
  LIBPORT_API utime_t utime();

  /// Return the arbitrary basis
  LIBPORT_API const boost::posix_time::ptime& utime_reference();

  /// Set the arbitrary basis
  LIBPORT_API void utime_reference_set(const boost::posix_time::ptime& ref);

  /// Convert from microseconds to timeval.
  timeval utime_to_timeval(utime_t t);

}

# include <libport/utime.hxx>

#endif // !LIBPORT_UTIME_HH
<|endoftext|>


<commit_before>/**
 ** \file libport/containers.hxx
 ** \brief Some syntactic sugar to look for things in STL containers.
 */

#ifndef LIBPORT_CONTAINERS_HXX
# define LIBPORT_CONTAINERS_HXX

# include <ostream>
# include <algorithm>
# include <functional>

# include "libport/containers.hh"

namespace libport
{

  // Object function to free members of a container.
  template<typename T>
  struct Delete : public std::unary_function<T, void>
  {
    void operator () (T t)
    {
      delete t;
    }
  };

  template<typename Container>
  void
  deep_clear (Container& c)
  {
    std::for_each (c.begin (), c.end (),
		   Delete<typename Container::value_type> ());
    c.clear ();
  }

  // Find \a v in the whole \a c.
  template<typename Container>
  inline typename Container::const_iterator
  find (const Container& c, const typename Container::value_type& v)
  {
    return std::find (c.begin (), c.end (), v);
  }

  // Find \a v in the whole \a c.
  template<typename Container>
  inline typename Container::iterator
  find (Container& c, const typename Container::value_type& v)
  {
    return std::find (c.begin (), c.end (), v);
  }

  template<typename Container>
  inline typename Container::mapped_type
  find0 (Container& c, const typename Container::key_type& k)
  {
    typename Container::const_iterator i = c.find(k);
    if (i != c.end())
      return i->second;
    else
      return 0;
  }

  // Apply \a f to all the members of \a c, and return it.
  template<typename Container, typename Functor>
  inline Functor&
  for_each (Container& c, Functor& f)
  {
    for (typename Container::const_iterator i = c.begin (), end = c.end();
	 i != end; ++i)
      f (*i);
    return f;
  }

  // Is \a v member of \a c?
  template<typename Container>
  inline bool
  has (const Container& c, const typename Container::value_type& v)
  {
    // We specify the instance to solve a conflict between the
    // two finds above, that compete against each other because
    // the parameter Container can embed a "const".
    return find<Container> (c, v) != c.end ();
  }

  // Is \a v member of \a c?
  template<typename Container>
  inline bool
  mhas (const Container& c, const typename Container::key_type& v)
  {
    return c.find(v) != c.end ();
  }

  template<typename Map>
  typename Map::iterator
  put (Map& map,
       const typename Map::key_type& key,
       const typename Map::mapped_type& value)
  {
    // See ``Efficient STL''.
    typename Map::iterator i = map.lower_bound (key);

    if (i != map.end () && !(map.key_comp () (key, i->first)))
      {
	// Update.
	i->second = value;
	return i;
      }
    else
      {
	// First insertion.
	typedef typename Map::value_type mvt;
	return map.insert (mvt (key, value)).first;
      }
  }

} // namespace libport

#endif // !LIBPORT_CONTAINERS_HXX
<commit_msg>Useless parens removal.<commit_after>/**
 ** \file libport/containers.hxx
 ** \brief Some syntactic sugar to look for things in STL containers.
 */

#ifndef LIBPORT_CONTAINERS_HXX
# define LIBPORT_CONTAINERS_HXX

# include <ostream>
# include <algorithm>
# include <functional>

# include "libport/containers.hh"

namespace libport
{

  // Object function to free members of a container.
  template<typename T>
  struct Delete : public std::unary_function<T, void>
  {
    void operator () (T t)
    {
      delete t;
    }
  };

  template<typename Container>
  void
  deep_clear (Container& c)
  {
    std::for_each (c.begin (), c.end (),
		   Delete<typename Container::value_type> ());
    c.clear ();
  }

  // Find \a v in the whole \a c.
  template<typename Container>
  inline typename Container::const_iterator
  find (const Container& c, const typename Container::value_type& v)
  {
    return std::find (c.begin (), c.end (), v);
  }

  // Find \a v in the whole \a c.
  template<typename Container>
  inline typename Container::iterator
  find (Container& c, const typename Container::value_type& v)
  {
    return std::find (c.begin (), c.end (), v);
  }

  template<typename Container>
  inline typename Container::mapped_type
  find0 (Container& c, const typename Container::key_type& k)
  {
    typename Container::const_iterator i = c.find(k);
    if (i != c.end())
      return i->second;
    else
      return 0;
  }

  // Apply \a f to all the members of \a c, and return it.
  template<typename Container, typename Functor>
  inline Functor&
  for_each (Container& c, Functor& f)
  {
    for (typename Container::const_iterator i = c.begin (), end = c.end();
	 i != end; ++i)
      f (*i);
    return f;
  }

  // Is \a v member of \a c?
  template<typename Container>
  inline bool
  has (const Container& c, const typename Container::value_type& v)
  {
    // We specify the instance to solve a conflict between the
    // two finds above, that compete against each other because
    // the parameter Container can embed a "const".
    return find<Container> (c, v) != c.end ();
  }

  // Is \a v member of \a c?
  template<typename Container>
  inline bool
  mhas (const Container& c, const typename Container::key_type& v)
  {
    return c.find(v) != c.end ();
  }

  template<typename Map>
  typename Map::iterator
  put (Map& map,
       const typename Map::key_type& key,
       const typename Map::mapped_type& value)
  {
    // See ``Efficient STL''.
    typename Map::iterator i = map.lower_bound (key);

    if (i != map.end () && !map.key_comp () (key, i->first))
      {
	// Update.
	i->second = value;
	return i;
      }
    else
      {
	// First insertion.
	typedef typename Map::value_type mvt;
	return map.insert (mvt (key, value)).first;
      }
  }

} // namespace libport

#endif // !LIBPORT_CONTAINERS_HXX
<|endoftext|>


<commit_before>/*
An integer M and a non-empty zero-indexed array A consisting of N non-negative integers are given. All integers in array A are less than or equal to M.
A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice of array A. The slice consists of the elements A[P], A[P + 1], ..., A[Q]. A distinct slice is a slice consisting of only unique numbers. That is, no individual number occurs more than once in the slice.
For example, consider integer M = 6 and array A such that:
    A[0] = 3
    A[1] = 4
    A[2] = 5
    A[3] = 5
    A[4] = 2
There are exactly nine distinct slices: (0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2), (3, 3), (3, 4) and (4, 4).
The goal is to calculate the number of distinct slices.
Write a function:
int solution(int M, vector<int> &A);
that, given an integer M and a non-empty zero-indexed array A consisting of N integers, returns the number of distinct slices.
If the number of distinct slices is greater than 1,000,000,000, the function should return 1,000,000,000.
For example, given integer M = 6 and array A such that:
    A[0] = 3
    A[1] = 4
    A[2] = 5
    A[3] = 5
    A[4] = 2
the function should return 9, as explained above.
Assume that:
N is an integer within the range [1..100,000];
M is an integer within the range [0..100,000];
each element of array A is an integer within the range [0..M].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(M), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Copyright 2009–2015 by Codility Limited. All Rights Reserved. Unauthorized copying, publication or disclosure prohibited.
*/
<commit_msg>Update solution.cpp<commit_after>// you can use includes, for example:
// #include <algorithm>
#include <bitset>

// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;

int solution(int M, vector<int> &A) {
    // for(unsigned int i=0; i<A.size(); ++i)
        // cout << A[i] << " ";
    // cout << endl;
    // write your code in C++11
    int i(0);
    int j(0);
    long count(0);
    bitset<100000> mybitset;
    while( i<A.size() ) {
        // cout << i << " " << j << " ";
        if( j<A.size() ) {
            if( mybitset[A[j]]==0 ) {
                mybitset[A[j]]= 1;
                count++;
                j++;
            }
            else {
                mybitset.reset();
                i++;
                j=i;
            }
        }
        else {
            count += (j-i)*(j-i-1)/2;
            i=j;
        }
        if( count>1000000000 )
            return 1000000000;
        // cout << count << endl;
    }
    return count;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../StroikaPreComp.h"

#include	<algorithm>
#include	<cstdlib>

#include	"../../Foundation/Characters/Format.h"
#include	"../../Foundation/Containers/Common.h"
#include	"../../Foundation/DataExchangeFormat/BadFormatException.h"
#include	"../../Foundation/Debug/Assertions.h"
#include	"../../Foundation/Execution/Exceptions.h"
#include	"../../Foundation/Memory/SmallStackBuffer.h"

#include	"HTTPResponse.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Containers;
using	namespace	Stroika::Foundation::Memory;

using	namespace	Stroika::Frameworks;
using	namespace	Stroika::Frameworks::WebServer;

/*
 ********************************************************************************
 ************************ WebServer::HTTPResponse *******************************
 ********************************************************************************
 */
namespace	{
	// Based on looking at a handlful of typical file sizes...5k to 80k, but ave around
	// 25 and median abit above 32k. Small, not very representative sampling. And the more we use
	// subscripts (script src=x) this number could shrink.
	//
	// MAY want to switch to using SmallStackBuffer<Byte> - but before doing so, do some cleanups of its bugs and make sure
	// its optimized about how much it copies etc. Its really only tuned for POD-types (OK here but not necessarily good about reallocs).
	//
	//		-- LGP 2011-07-06
	const	size_t	kMinResponseBufferReserve_				=	32 * 1024;
	const	size_t	kResponseBufferReallocChunkSizeReserve_	=	16 * 1024;
}

HTTPResponse::HTTPResponse (const IO::Network::Socket& s,  Streams::BinaryOutputStream& outStream, const InternetMediaType& ct)
	: fSocket_ (s)
	, fOutStream_ (outStream)
	, fState_ (eInProgress)
	, fStatus_ (StatusCodes::kOK)
	, fHeaders_ ()
	, fContentType_ (ct)
	, fBytes_ ()
{
	AddHeader (L"Server", L"Stroka-Based-Web-Server");
}

void	HTTPResponse::SetContentType (const InternetMediaType& contentType)
{
	Require (fState_ == eInProgress);
	fContentType_ = contentType;
}

void	HTTPResponse::SetStatus (Status newStatus)
{
	Require (fState_ == eInProgress);
	fStatus_ = newStatus;
}

void	HTTPResponse::AddHeader (String headerName, String value)
{
	Require (fState_ == eInProgress);
	ClearHeader (headerName);
	fHeaders_.insert (map<String,String>::value_type (headerName, value));
}

void	HTTPResponse::ClearHeader ()
{
	Require (fState_ == eInProgress);
	fHeaders_.clear ();
}

void	HTTPResponse::ClearHeader (String headerName)
{
	Require (fState_ == eInProgress);
	map<String,String>::iterator i = fHeaders_.find (headerName);
	if (i != fHeaders_.end ()) {
		fHeaders_.erase (i);
	}
}

void	HTTPResponse::Flush ()
{
	if (fState_ == eInProgress) {
		{
			wstring	statusMsg;
			switch (fStatus_) {
				case StatusCodes::kOK:					statusMsg = L"OK"; break;
				case StatusCodes::kMovedPermanently:	statusMsg = L"Moved Permanently"; break;
			}
			wstring	version	=	L"1.1";
			wstring	tmp	=	Characters::Format (L"HTTP/%s %d %s\r\n", version.c_str (), fStatus_, statusMsg.c_str ());
			string	utf8	=	String (tmp).AsUTF8 ();
			fOutStream_.Write (reinterpret_cast<const Byte*> (Containers::Start (utf8)), reinterpret_cast<const Byte*> (Containers::End (utf8)));
		}

		for (map<String,String>::const_iterator i = fHeaders_.begin (); i != fHeaders_.end (); ++i) {
			wstring	tmp	=	Characters::Format (L"%s: %s\r\n", i->first.As<wstring> ().c_str (), i->second.As<wstring> ().c_str ());
			string	utf8	=	String (tmp).AsUTF8 ();
			fOutStream_.Write (reinterpret_cast<const Byte*> (Containers::Start (utf8)), reinterpret_cast<const Byte*> (Containers::End (utf8)));
		}

		const char	kCRLF[]	=	"\r\n";
		fOutStream_.Write (reinterpret_cast<const Byte*> (kCRLF), reinterpret_cast<const Byte*> (kCRLF + 2));
		fState_ = eInProgressHeaderState;
	}
	// write BYTES to fOutStream
	if (not fBytes_.empty ()) {
		Assert (not fState_ == eCompleted);	// We PREVENT any writes when completed
		fOutStream_.Write (Containers::Start (fBytes_), Containers::End (fBytes_));
		fBytes_.clear ();
	}
}

void	HTTPResponse::End ()
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Flush ();
	fState_ = eCompleted;
}

void	HTTPResponse::Kill ()
{
	if (fState_ != eCompleted) {
		fState_ = eCompleted;
		fSocket_.Close ();
	}
}

void	HTTPResponse::Redirect (const wstring& url)
{
	Require (fState_ == eInProgress);
	fBytes_.clear ();

	// PERHAPS should clear some header values???
	AddHeader (L"Connection", L"close");	// needed for redirect
	AddHeader (L"Location", url);			// needed for redirect
	SetStatus (StatusCodes::kMovedPermanently);
	Flush ();
	fState_ = eCompleted;
}

void	HTTPResponse::write (const Byte* s, const Byte* e)
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Require (s <= e);
	if (s < e) {
		Containers::ReserveSpeedTweekAddN (fBytes_, (e - s), kResponseBufferReallocChunkSizeReserve_);
		fBytes_.insert (fBytes_.end (), s, e);
	}
}

void	HTTPResponse::write (const wchar_t* s, const wchar_t* e)
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Require (s <= e);
	if (s < e) {
		wstring tmp = wstring (s,e);
		string utf8 = String (tmp).AsUTF8 ();
		if (not utf8.empty ()) {
			fBytes_.insert (fBytes_.end (), reinterpret_cast<const Byte*> (utf8.c_str ()), reinterpret_cast<const Byte*> (utf8.c_str () + utf8.length ()));
		}
	}
}
<commit_msg>fixed typo in HTTPResponse::Flush () assertion<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2011.  All rights reserved
 */
#include	"../StroikaPreComp.h"

#include	<algorithm>
#include	<cstdlib>

#include	"../../Foundation/Characters/Format.h"
#include	"../../Foundation/Containers/Common.h"
#include	"../../Foundation/DataExchangeFormat/BadFormatException.h"
#include	"../../Foundation/Debug/Assertions.h"
#include	"../../Foundation/Execution/Exceptions.h"
#include	"../../Foundation/Memory/SmallStackBuffer.h"

#include	"HTTPResponse.h"

using	namespace	Stroika::Foundation;
using	namespace	Stroika::Foundation::Containers;
using	namespace	Stroika::Foundation::Memory;

using	namespace	Stroika::Frameworks;
using	namespace	Stroika::Frameworks::WebServer;

/*
 ********************************************************************************
 ************************ WebServer::HTTPResponse *******************************
 ********************************************************************************
 */
namespace	{
	// Based on looking at a handlful of typical file sizes...5k to 80k, but ave around
	// 25 and median abit above 32k. Small, not very representative sampling. And the more we use
	// subscripts (script src=x) this number could shrink.
	//
	// MAY want to switch to using SmallStackBuffer<Byte> - but before doing so, do some cleanups of its bugs and make sure
	// its optimized about how much it copies etc. Its really only tuned for POD-types (OK here but not necessarily good about reallocs).
	//
	//		-- LGP 2011-07-06
	const	size_t	kMinResponseBufferReserve_				=	32 * 1024;
	const	size_t	kResponseBufferReallocChunkSizeReserve_	=	16 * 1024;
}

HTTPResponse::HTTPResponse (const IO::Network::Socket& s,  Streams::BinaryOutputStream& outStream, const InternetMediaType& ct)
	: fSocket_ (s)
	, fOutStream_ (outStream)
	, fState_ (eInProgress)
	, fStatus_ (StatusCodes::kOK)
	, fHeaders_ ()
	, fContentType_ (ct)
	, fBytes_ ()
{
	AddHeader (L"Server", L"Stroka-Based-Web-Server");
}

void	HTTPResponse::SetContentType (const InternetMediaType& contentType)
{
	Require (fState_ == eInProgress);
	fContentType_ = contentType;
}

void	HTTPResponse::SetStatus (Status newStatus)
{
	Require (fState_ == eInProgress);
	fStatus_ = newStatus;
}

void	HTTPResponse::AddHeader (String headerName, String value)
{
	Require (fState_ == eInProgress);
	ClearHeader (headerName);
	fHeaders_.insert (map<String,String>::value_type (headerName, value));
}

void	HTTPResponse::ClearHeader ()
{
	Require (fState_ == eInProgress);
	fHeaders_.clear ();
}

void	HTTPResponse::ClearHeader (String headerName)
{
	Require (fState_ == eInProgress);
	map<String,String>::iterator i = fHeaders_.find (headerName);
	if (i != fHeaders_.end ()) {
		fHeaders_.erase (i);
	}
}

void	HTTPResponse::Flush ()
{
	if (fState_ == eInProgress) {
		{
			wstring	statusMsg;
			switch (fStatus_) {
				case StatusCodes::kOK:					statusMsg = L"OK"; break;
				case StatusCodes::kMovedPermanently:	statusMsg = L"Moved Permanently"; break;
			}
			wstring	version	=	L"1.1";
			wstring	tmp	=	Characters::Format (L"HTTP/%s %d %s\r\n", version.c_str (), fStatus_, statusMsg.c_str ());
			string	utf8	=	String (tmp).AsUTF8 ();
			fOutStream_.Write (reinterpret_cast<const Byte*> (Containers::Start (utf8)), reinterpret_cast<const Byte*> (Containers::End (utf8)));
		}

		for (map<String,String>::const_iterator i = fHeaders_.begin (); i != fHeaders_.end (); ++i) {
			wstring	tmp	=	Characters::Format (L"%s: %s\r\n", i->first.As<wstring> ().c_str (), i->second.As<wstring> ().c_str ());
			string	utf8	=	String (tmp).AsUTF8 ();
			fOutStream_.Write (reinterpret_cast<const Byte*> (Containers::Start (utf8)), reinterpret_cast<const Byte*> (Containers::End (utf8)));
		}

		const char	kCRLF[]	=	"\r\n";
		fOutStream_.Write (reinterpret_cast<const Byte*> (kCRLF), reinterpret_cast<const Byte*> (kCRLF + 2));
		fState_ = eInProgressHeaderState;
	}
	// write BYTES to fOutStream
	if (not fBytes_.empty ()) {
		Assert (fState_ != eCompleted);	// We PREVENT any writes when completed
		fOutStream_.Write (Containers::Start (fBytes_), Containers::End (fBytes_));
		fBytes_.clear ();
	}
}

void	HTTPResponse::End ()
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Flush ();
	fState_ = eCompleted;
}

void	HTTPResponse::Kill ()
{
	if (fState_ != eCompleted) {
		fState_ = eCompleted;
		fSocket_.Close ();
	}
}

void	HTTPResponse::Redirect (const wstring& url)
{
	Require (fState_ == eInProgress);
	fBytes_.clear ();

	// PERHAPS should clear some header values???
	AddHeader (L"Connection", L"close");	// needed for redirect
	AddHeader (L"Location", url);			// needed for redirect
	SetStatus (StatusCodes::kMovedPermanently);
	Flush ();
	fState_ = eCompleted;
}

void	HTTPResponse::write (const Byte* s, const Byte* e)
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Require (s <= e);
	if (s < e) {
		Containers::ReserveSpeedTweekAddN (fBytes_, (e - s), kResponseBufferReallocChunkSizeReserve_);
		fBytes_.insert (fBytes_.end (), s, e);
	}
}

void	HTTPResponse::write (const wchar_t* s, const wchar_t* e)
{
	Require ((fState_ == eInProgress) or (fState_ == eInProgressHeaderState));
	Require (s <= e);
	if (s < e) {
		wstring tmp = wstring (s,e);
		string utf8 = String (tmp).AsUTF8 ();
		if (not utf8.empty ()) {
			fBytes_.insert (fBytes_.end (), reinterpret_cast<const Byte*> (utf8.c_str ()), reinterpret_cast<const Byte*> (utf8.c_str () + utf8.length ()));
		}
	}
}
<|endoftext|>