<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of mcompositor.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#define GLX_GLXEXT_PROTOTYPES 1
#define GLX_EXT_texture_from_pixmap 1

#include "mtexturepixmapitem.h"
#include "mtexturepixmapitem_p.h"

#include <QPainterPath>
#include <QRect>
#include <QGLContext>
#include <QX11Info>
#include <vector>

#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <GL/glxext.h>

#if defined(GLX_VERSION_1_3)
#ifndef GLX_TEXTURE_2D_BIT_EXT
#define GLX_TEXTURE_2D_BIT_EXT             0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT      0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT        0x20D0
#define GLX_BIND_TO_TEXTURE_RGBA_EXT       0x20D1
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT     0x20D2
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT    0x20D3
#define GLX_Y_INVERTED_EXT                 0x20D4
#define GLX_TEXTURE_FORMAT_EXT             0x20D5
#define GLX_TEXTURE_TARGET_EXT             0x20D6
#define GLX_MIPMAP_TEXTURE_EXT             0x20D7
#define GLX_TEXTURE_FORMAT_NONE_EXT        0x20D8
#define GLX_TEXTURE_FORMAT_RGB_EXT         0x20D9
#define GLX_TEXTURE_FORMAT_RGBA_EXT        0x20DA
#define GLX_TEXTURE_2D_EXT                 0x20DC
#define GLX_TEXTURE_RECTANGLE_EXT          0x20DD
#define GLX_FRONT_LEFT_EXT                 0x20DE
#endif

typedef void (*_glx_bind)(Display *, GLXDrawable, int , const int *);
typedef void (*_glx_release)(Display *, GLXDrawable, int);
static  _glx_bind glXBindTexImageEXT = 0;
static  _glx_release glXReleaseTexImageEXT = 0;
static GLXFBConfig config = 0;
static GLXFBConfig configAlpha = 0;

static bool hasTextureFromPixmap()
{
    static bool hasTfp = false;

    if (!hasTfp) {
        hasTfp = true;

        QList<QByteArray> exts = QByteArray(glXQueryExtensionsString(QX11Info::display(), QX11Info::appScreen())).split(' ');
        if (exts.contains("GLX_EXT_texture_from_pixmap")) {
            glXBindTexImageEXT = (_glx_bind) glXGetProcAddress((const GLubyte *)"glXBindTexImageEXT");
            glXReleaseTexImageEXT = (_glx_release) glXGetProcAddress((const GLubyte *)"glXReleaseTexImageEXT");
        }
    }
    return glXBindTexImageEXT && glXReleaseTexImageEXT;
}
#endif

void MTexturePixmapItem::init()
{
    MWindowPropertyCache *pc = propertyCache();
    if (isValid() && !pc->isMapped()) {
        qWarning("MTexturePixmapItem::%s(): Failed getting offscreen pixmap",
                 __func__);
        return;
    } else if (!isValid())
        return;

    d->glpixmap = 0;

    d->custom_tfp = !hasTextureFromPixmap();
    saveBackingStore();

    if (d->custom_tfp) {
        initCustomTfp();
        return;
    }
    const int pixmapAttribs[] = {
        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
        GLX_TEXTURE_FORMAT_EXT, propertyCache()->hasAlpha() ?
                GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
        None
    };

    if ((!pc->hasAlpha() && !config) || (pc->hasAlpha() && !configAlpha)) {
        Display *display = QX11Info::display();
        int screen = QX11Info::appScreen();

        int pixmap_config[] = {
            pc->hasAlpha() ? GLX_BIND_TO_TEXTURE_RGBA_EXT :
                             GLX_BIND_TO_TEXTURE_RGB_EXT, True,
            GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
            GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
            GLX_DOUBLEBUFFER, True,
            GLX_Y_INVERTED_EXT, GLX_DONT_CARE,
            None
        };

        int c = 0;
        GLXFBConfig *configs = 0;
        configs = glXChooseFBConfig(display, screen, pixmap_config, &c);
        if (!configs) {
            qWarning("No appropriate GLXFBconfig found!"
                     "Falling back to custom texture to pixmap ");
            d->custom_tfp = true;
            initCustomTfp();
            return;
        }

        int inverted;
        glXGetFBConfigAttrib(display, configs[0], GLX_Y_INVERTED_EXT, &inverted);
        if (pc->hasAlpha()) {
            configAlpha = configs[0];
            d->inverted_texture = inverted ? true : false;
        } else {
            config = configs[0];
            d->inverted_texture = inverted ? true : false;
        }
        XFree(configs);
    }

    glGenTextures(1, &d->textureId);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, d->textureId);
    d->glpixmap = glXCreatePixmap(QX11Info::display(), pc->hasAlpha() ?
                        configAlpha : config, d->windowp, pixmapAttribs);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glXBindTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
}

MTexturePixmapItem::MTexturePixmapItem(Window window,
                                       MWindowPropertyCache *pc,
                                       QGraphicsItem *parent)
    : MCompositeWindow(window, pc, parent),
      d(new MTexturePixmapPrivate(window, this))
{
    init();
}

void MTexturePixmapItem::saveBackingStore()
{
    d->saveBackingStore();
}

void MTexturePixmapItem::rebindPixmap()
{
    const int pixmapAttribs[] = {
        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
        GLX_TEXTURE_FORMAT_EXT, propertyCache()->hasAlpha() ?
        GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
        None
    };

    if (!d->custom_tfp) {
        Display *display = QX11Info::display();
        glXReleaseTexImageEXT(display, d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(display, d->glpixmap);
        d->glpixmap = glXCreatePixmap(display, propertyCache()->hasAlpha() ?
                                                 configAlpha : config,
                                                 d->windowp, pixmapAttribs);
        glBindTexture(GL_TEXTURE_2D, d->textureId);
        glXBindTexImageEXT(display, d->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
    }
}

void MTexturePixmapItem::enableDirectFbRendering()
{
    if (d->item->propertyCache())
        d->item->propertyCache()->damageTracking(false);

    if ((d->direct_fb_render || d->glpixmap == 0) && !d->custom_tfp)
        return;

    d->direct_fb_render = true;
    // Just free the off-screen surface but re-use the
    // existing texture id, so don't delete it yet.

    if (!d->custom_tfp) {
        glXReleaseTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(QX11Info::display(), d->glpixmap);
        d->glpixmap = 0;
    }

    if (d->windowp) {
        XFreePixmap(QX11Info::display(), d->windowp);
        d->windowp = 0;
    }
    XCompositeUnredirectWindow(QX11Info::display(), window(),
                               CompositeRedirectManual);
    XSync(QX11Info::display(), FALSE);
}

void MTexturePixmapItem::enableRedirectedRendering()
{
    if (d->item->propertyCache())
        d->item->propertyCache()->damageTracking(true);

    if ((!d->direct_fb_render || d->glpixmap != 0) && !d->custom_tfp)
        return;

    d->direct_fb_render = false;
    XCompositeRedirectWindow(QX11Info::display(), window(),
                             CompositeRedirectManual);
    XSync(QX11Info::display(), FALSE);
    saveBackingStore();
    updateWindowPixmap();
}

bool MTexturePixmapItem::isDirectRendered() const
{
    return d->direct_fb_render;
}

MTexturePixmapItem::~MTexturePixmapItem()
{
    cleanup();
    delete d;
}

void MTexturePixmapItem::initCustomTfp()
{
    glGenTextures(1, &d->ctextureId);

    glBindTexture(GL_TEXTURE_2D, d->ctextureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    d->inverted_texture = false;
}

void MTexturePixmapItem::cleanup()
{
    if (!d->custom_tfp) {
        glXReleaseTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(QX11Info::display(), d->glpixmap);
        glDeleteTextures(1, &d->textureId);
    } else
        glDeleteTextures(1, &d->ctextureId);

    if (d->windowp)
        XFreePixmap(QX11Info::display(), d->windowp);
}

void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num,
                                            Time when)
{
    Q_UNUSED(rects);
    Q_UNUSED(num);

    if (isWindowTransitioning() || d->direct_fb_render || !windowVisible())
        return;

    // Our very own custom texture from pixmap
    if (d->custom_tfp && d->windowp) {
        QPixmap qp = QPixmap::fromX11Pixmap(d->windowp);

        QT_TRY {
            QImage img = d->glwidget->convertToGLFormat(qp.toImage());
            glBindTexture(GL_TEXTURE_2D, d->ctextureId);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0,
                         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
       } QT_CATCH(std::bad_alloc e) {
           /* XGetImage() failed, the window has been unmapped. */;
       }
    }
    update();
}

void MTexturePixmapItem::paint(QPainter *painter,
                                 const QStyleOptionGraphicsItem *option,
                                 QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

#if QT_VERSION < 0x040600
    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL)
        return;
#else
    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL2 &&
        painter->paintEngine()->type()  != QPaintEngine::OpenGL) {
        return;
    }
#endif

#if (QT_VERSION >= 0x040600)
    painter->beginNativePainting();
#endif

    glEnable(GL_TEXTURE_2D);
    if (propertyCache()->hasAlpha() || (opacity() < 1.0f && !dimmedEffect()) ) {
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColor4f(1.0, 1.0, 1.0, opacity());
    }

    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);

    const QRegion &shape = propertyCache()->shapeRegion();
    bool shape_on = !QRegion(boundingRect().toRect()).subtracted(shape).isEmpty();
    bool scissor_on = d->damageRegion.numRects() > 1 || shape_on;

    if (scissor_on)
        glEnable(GL_SCISSOR_TEST);

    // Damage regions taking precedence over shape rects
    if (d->damageRegion.numRects() > 1) {
        for (int i = 0; i < d->damageRegion.numRects(); ++i) {
            glScissor(d->damageRegion.rects().at(i).x(),
                      d->brect.height() -
                      (d->damageRegion.rects().at(i).y() +
                       d->damageRegion.rects().at(i).height()),
                      d->damageRegion.rects().at(i).width(),
                      d->damageRegion.rects().at(i).height());
            d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());
        }
    } else if (shape_on) {
        // draw a shaped window using glScissor
        for (int i = 0; i < shape.numRects(); ++i) {
            glScissor(shape.rects().at(i).x(),
                      d->brect.height() -
                      (shape.rects().at(i).y() +
                       shape.rects().at(i).height()),
                      shape.rects().at(i).width(),
                      shape.rects().at(i).height());
            d->drawTexture(painter->combinedTransform(),
                           boundingRect(), opacity());
        }
    } else
        d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());

    if (scissor_on)
        glDisable(GL_SCISSOR_TEST);

    glDisable(GL_BLEND);

#if (QT_VERSION >= 0x040600)
    painter->endNativePainting();
#endif

}

void MTexturePixmapItem::windowRaised()
{
    d->windowRaised();
}

void MTexturePixmapItem::resize(int w, int h)
{
    d->resize(w, h);
}

QSizeF MTexturePixmapItem::sizeHint(Qt::SizeHint, const QSizeF &) const
{
    return boundingRect().size();
}

QRectF MTexturePixmapItem::boundingRect() const
{
    return d->brect;
}

void MTexturePixmapItem::clearTexture()
{
    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, 0);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
<commit_msg>Fixes: http://bugs.meego.com/show_bug.cgi?id=8957 Changes: On the GLX backend, ensure that the window's pixmap is not null before rebinding it. RevBy: TrustMe<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of mcompositor.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#define GLX_GLXEXT_PROTOTYPES 1
#define GLX_EXT_texture_from_pixmap 1

#include "mtexturepixmapitem.h"
#include "mtexturepixmapitem_p.h"

#include <QPainterPath>
#include <QRect>
#include <QGLContext>
#include <QX11Info>
#include <vector>

#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <GL/glxext.h>

#if defined(GLX_VERSION_1_3)
#ifndef GLX_TEXTURE_2D_BIT_EXT
#define GLX_TEXTURE_2D_BIT_EXT             0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT      0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT        0x20D0
#define GLX_BIND_TO_TEXTURE_RGBA_EXT       0x20D1
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT     0x20D2
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT    0x20D3
#define GLX_Y_INVERTED_EXT                 0x20D4
#define GLX_TEXTURE_FORMAT_EXT             0x20D5
#define GLX_TEXTURE_TARGET_EXT             0x20D6
#define GLX_MIPMAP_TEXTURE_EXT             0x20D7
#define GLX_TEXTURE_FORMAT_NONE_EXT        0x20D8
#define GLX_TEXTURE_FORMAT_RGB_EXT         0x20D9
#define GLX_TEXTURE_FORMAT_RGBA_EXT        0x20DA
#define GLX_TEXTURE_2D_EXT                 0x20DC
#define GLX_TEXTURE_RECTANGLE_EXT          0x20DD
#define GLX_FRONT_LEFT_EXT                 0x20DE
#endif

typedef void (*_glx_bind)(Display *, GLXDrawable, int , const int *);
typedef void (*_glx_release)(Display *, GLXDrawable, int);
static  _glx_bind glXBindTexImageEXT = 0;
static  _glx_release glXReleaseTexImageEXT = 0;
static GLXFBConfig config = 0;
static GLXFBConfig configAlpha = 0;

static bool hasTextureFromPixmap()
{
    static bool hasTfp = false;

    if (!hasTfp) {
        hasTfp = true;

        QList<QByteArray> exts = QByteArray(glXQueryExtensionsString(QX11Info::display(), QX11Info::appScreen())).split(' ');
        if (exts.contains("GLX_EXT_texture_from_pixmap")) {
            glXBindTexImageEXT = (_glx_bind) glXGetProcAddress((const GLubyte *)"glXBindTexImageEXT");
            glXReleaseTexImageEXT = (_glx_release) glXGetProcAddress((const GLubyte *)"glXReleaseTexImageEXT");
        }
    }
    return glXBindTexImageEXT && glXReleaseTexImageEXT;
}
#endif

void MTexturePixmapItem::init()
{
    MWindowPropertyCache *pc = propertyCache();
    if (isValid() && !pc->isMapped()) {
        qWarning("MTexturePixmapItem::%s(): Failed getting offscreen pixmap",
                 __func__);
        return;
    } else if (!isValid())
        return;

    d->glpixmap = 0;

    d->custom_tfp = !hasTextureFromPixmap();
    saveBackingStore();

    if (d->custom_tfp) {
        initCustomTfp();
        return;
    }
    const int pixmapAttribs[] = {
        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
        GLX_TEXTURE_FORMAT_EXT, propertyCache()->hasAlpha() ?
                GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
        None
    };

    if ((!pc->hasAlpha() && !config) || (pc->hasAlpha() && !configAlpha)) {
        Display *display = QX11Info::display();
        int screen = QX11Info::appScreen();

        int pixmap_config[] = {
            pc->hasAlpha() ? GLX_BIND_TO_TEXTURE_RGBA_EXT :
                             GLX_BIND_TO_TEXTURE_RGB_EXT, True,
            GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
            GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
            GLX_DOUBLEBUFFER, True,
            GLX_Y_INVERTED_EXT, GLX_DONT_CARE,
            None
        };

        int c = 0;
        GLXFBConfig *configs = 0;
        configs = glXChooseFBConfig(display, screen, pixmap_config, &c);
        if (!configs) {
            qWarning("No appropriate GLXFBconfig found!"
                     "Falling back to custom texture to pixmap ");
            d->custom_tfp = true;
            initCustomTfp();
            return;
        }

        int inverted;
        glXGetFBConfigAttrib(display, configs[0], GLX_Y_INVERTED_EXT, &inverted);
        if (pc->hasAlpha()) {
            configAlpha = configs[0];
            d->inverted_texture = inverted ? true : false;
        } else {
            config = configs[0];
            d->inverted_texture = inverted ? true : false;
        }
        XFree(configs);
    }

    glGenTextures(1, &d->textureId);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, d->textureId);
    d->glpixmap = glXCreatePixmap(QX11Info::display(), pc->hasAlpha() ?
                        configAlpha : config, d->windowp, pixmapAttribs);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glXBindTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
}

MTexturePixmapItem::MTexturePixmapItem(Window window,
                                       MWindowPropertyCache *pc,
                                       QGraphicsItem *parent)
    : MCompositeWindow(window, pc, parent),
      d(new MTexturePixmapPrivate(window, this))
{
    init();
}

void MTexturePixmapItem::saveBackingStore()
{
    d->saveBackingStore();
}

void MTexturePixmapItem::rebindPixmap()
{
    const int pixmapAttribs[] = {
        GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
        GLX_TEXTURE_FORMAT_EXT, propertyCache()->hasAlpha() ?
        GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
        None
    };

    if (!d->custom_tfp && d->windowp) {
        Display *display = QX11Info::display();
        glXReleaseTexImageEXT(display, d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(display, d->glpixmap);
        d->glpixmap = glXCreatePixmap(display, propertyCache()->hasAlpha() ?
                                                 configAlpha : config,
                                                 d->windowp, pixmapAttribs);
        glBindTexture(GL_TEXTURE_2D, d->textureId);
        glXBindTexImageEXT(display, d->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
    }
}

void MTexturePixmapItem::enableDirectFbRendering()
{
    if (d->item->propertyCache())
        d->item->propertyCache()->damageTracking(false);

    if ((d->direct_fb_render || d->glpixmap == 0) && !d->custom_tfp)
        return;

    d->direct_fb_render = true;
    // Just free the off-screen surface but re-use the
    // existing texture id, so don't delete it yet.

    if (!d->custom_tfp) {
        glXReleaseTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(QX11Info::display(), d->glpixmap);
        d->glpixmap = 0;
    }

    if (d->windowp) {
        XFreePixmap(QX11Info::display(), d->windowp);
        d->windowp = 0;
    }
    XCompositeUnredirectWindow(QX11Info::display(), window(),
                               CompositeRedirectManual);
    XSync(QX11Info::display(), FALSE);
}

void MTexturePixmapItem::enableRedirectedRendering()
{
    if (d->item->propertyCache())
        d->item->propertyCache()->damageTracking(true);

    if ((!d->direct_fb_render || d->glpixmap != 0) && !d->custom_tfp)
        return;

    d->direct_fb_render = false;
    XCompositeRedirectWindow(QX11Info::display(), window(),
                             CompositeRedirectManual);
    XSync(QX11Info::display(), FALSE);
    saveBackingStore();
    updateWindowPixmap();
}

bool MTexturePixmapItem::isDirectRendered() const
{
    return d->direct_fb_render;
}

MTexturePixmapItem::~MTexturePixmapItem()
{
    cleanup();
    delete d;
}

void MTexturePixmapItem::initCustomTfp()
{
    glGenTextures(1, &d->ctextureId);

    glBindTexture(GL_TEXTURE_2D, d->ctextureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    d->inverted_texture = false;
}

void MTexturePixmapItem::cleanup()
{
    if (!d->custom_tfp) {
        glXReleaseTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT);
        glXDestroyPixmap(QX11Info::display(), d->glpixmap);
        glDeleteTextures(1, &d->textureId);
    } else
        glDeleteTextures(1, &d->ctextureId);

    if (d->windowp)
        XFreePixmap(QX11Info::display(), d->windowp);
}

void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num,
                                            Time when)
{
    Q_UNUSED(rects);
    Q_UNUSED(num);

    if (isWindowTransitioning() || d->direct_fb_render || !windowVisible())
        return;

    // Our very own custom texture from pixmap
    if (d->custom_tfp && d->windowp) {
        QPixmap qp = QPixmap::fromX11Pixmap(d->windowp);

        QT_TRY {
            QImage img = d->glwidget->convertToGLFormat(qp.toImage());
            glBindTexture(GL_TEXTURE_2D, d->ctextureId);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0,
                         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
       } QT_CATCH(std::bad_alloc e) {
           /* XGetImage() failed, the window has been unmapped. */;
       }
    }
    update();
}

void MTexturePixmapItem::paint(QPainter *painter,
                                 const QStyleOptionGraphicsItem *option,
                                 QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

#if QT_VERSION < 0x040600
    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL)
        return;
#else
    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL2 &&
        painter->paintEngine()->type()  != QPaintEngine::OpenGL) {
        return;
    }
#endif

#if (QT_VERSION >= 0x040600)
    painter->beginNativePainting();
#endif

    glEnable(GL_TEXTURE_2D);
    if (propertyCache()->hasAlpha() || (opacity() < 1.0f && !dimmedEffect()) ) {
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColor4f(1.0, 1.0, 1.0, opacity());
    }

    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);

    const QRegion &shape = propertyCache()->shapeRegion();
    bool shape_on = !QRegion(boundingRect().toRect()).subtracted(shape).isEmpty();
    bool scissor_on = d->damageRegion.numRects() > 1 || shape_on;

    if (scissor_on)
        glEnable(GL_SCISSOR_TEST);

    // Damage regions taking precedence over shape rects
    if (d->damageRegion.numRects() > 1) {
        for (int i = 0; i < d->damageRegion.numRects(); ++i) {
            glScissor(d->damageRegion.rects().at(i).x(),
                      d->brect.height() -
                      (d->damageRegion.rects().at(i).y() +
                       d->damageRegion.rects().at(i).height()),
                      d->damageRegion.rects().at(i).width(),
                      d->damageRegion.rects().at(i).height());
            d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());
        }
    } else if (shape_on) {
        // draw a shaped window using glScissor
        for (int i = 0; i < shape.numRects(); ++i) {
            glScissor(shape.rects().at(i).x(),
                      d->brect.height() -
                      (shape.rects().at(i).y() +
                       shape.rects().at(i).height()),
                      shape.rects().at(i).width(),
                      shape.rects().at(i).height());
            d->drawTexture(painter->combinedTransform(),
                           boundingRect(), opacity());
        }
    } else
        d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());

    if (scissor_on)
        glDisable(GL_SCISSOR_TEST);

    glDisable(GL_BLEND);

#if (QT_VERSION >= 0x040600)
    painter->endNativePainting();
#endif

}

void MTexturePixmapItem::windowRaised()
{
    d->windowRaised();
}

void MTexturePixmapItem::resize(int w, int h)
{
    d->resize(w, h);
}

QSizeF MTexturePixmapItem::sizeHint(Qt::SizeHint, const QSizeF &) const
{
    return boundingRect().size();
}

QRectF MTexturePixmapItem::boundingRect() const
{
    return d->brect;
}

void MTexturePixmapItem::clearTexture()
{
    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, 0);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
<|endoftext|>


<commit_before>#pragma once
#include "../../src/signal_handlers.h"
#include "../../src/utils/dstring.h"
#include "../../src/utils/dstring_factory.h"
#include <pwd.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>

namespace doormat {
    using ::signals_handlers::set;
    using ::signals_handlers::block_all;
    using ::signals_handlers::unblock_all;
    using ::dstring;
    using ::dstring_factory;
}<commit_msg>do not exports dstring anymore<commit_after>#pragma once
#include "../../src/signal_handlers.h"
#include "../../src/utils/dstring.h"
#include "../../src/utils/dstring_factory.h"
#include <pwd.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>

namespace doormat {
    using ::signals_handlers::set;
    using ::signals_handlers::block_all;
	using ::signals_handlers::unblock_all;
}
<|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 Contains allocation utilities
 */

#pragma once

#include <memory>

namespace etl {

/*!
 * \brief Allocated for aligned memory
 * \tparam Expr The expression typoe
 * \tparam A The alignment
 */
template <typename Expr, std::size_t A>
struct aligned_allocator {
    /*!
     * \brief Allocate a block of memory of *size* elements
     * \param size The number of elements
     * \return A pointer to the allocated memory
     */
    template <typename T>
    static T* allocate(std::size_t size) {
        auto required_bytes = sizeof(T) * size;
        auto offset         = (A - 1) + sizeof(uintptr_t);
        auto orig           = malloc(required_bytes + offset);

        if (!orig) {
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    /*!
     * \brief Release the memory
     * \param ptr The pointer to the memory to be released
     */
    template <typename T>
    static void release(T* ptr) {
        //Note the const_cast is only to allow compilation
        free((reinterpret_cast<void**>(const_cast<std::remove_const_t<T>*>(ptr)))[-1]);
    }
};

/*!
 * \brief Allocate an array of the given size for the given type
 * \param size The number of elements
 * \return An unique pointer to the memory
 */
template <typename T>
auto allocate(std::size_t size) {
    return std::make_unique<T[]>(size);
}

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
T* aligned_allocate(std::size_t size) {
    return aligned_allocator<void, 32>::allocate<T>(size);
}

/*!
 * \brief Release some aligned memory
 * \param ptr The ptr to the aligned memory
 */
template <typename T>
void aligned_release(T* ptr) {
    return aligned_allocator<void, 32>::release<T>(ptr);
}

/*!
 * \brief RAII wrapper for allocated aligned memory
 */
template <typename T>
struct aligned_ptr {
    T* ptr; ///< The raw pointer

    /*!
     * \brief Build an aligned_ptr managing the given pointer
     */
    aligned_ptr(T* ptr) : ptr(ptr) {}

    aligned_ptr(const aligned_ptr& rhs) = delete;
    aligned_ptr& operator=(const aligned_ptr& rhs) = delete;

    /*!
     * \brief Move construct an aligned_ptr
     * \param rhs The pointer to move
     */
    aligned_ptr(aligned_ptr&& rhs) : ptr(rhs.ptr) {
        rhs.ptr = nullptr;
    }

    /*!
     * \brief Move assign an aligned_ptr
     * \param rhs The pointer to move
     * \return the aligned_ptr
     */
    aligned_ptr& operator=(aligned_ptr&& rhs){
        if(this != &rhs){
            ptr = rhs.ptr;
            rhs.ptr = nullptr;
        }

        return *this;
    }

    /*!
     * \brief Returns a reference to the element at psition i
     */
    inline T& operator[](std::size_t i){
        return ptr[i];
    }

    /*!
     * \brief Returns a reference to the element at psition i
     */
    inline const T& operator[](std::size_t i) const {
        return ptr[i];
    }

    /*!
     * \brief Destruct the aligned_ptr and release the aligned memory
     */
    ~aligned_ptr(){
        if(ptr){
            aligned_release(ptr);
        }
    }

    /*!
     * \brief Returns the raw underlying pointer
     */
    T* get(){
        return ptr;
    }
};

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
aligned_ptr<T> aligned_allocate_auto(std::size_t size) {
    return {aligned_allocate<T>(size)};
}

} //end of namespace etl
<commit_msg>Make the constructor explicit<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 Contains allocation utilities
 */

#pragma once

#include <memory>

namespace etl {

/*!
 * \brief Allocated for aligned memory
 * \tparam Expr The expression typoe
 * \tparam A The alignment
 */
template <typename Expr, std::size_t A>
struct aligned_allocator {
    /*!
     * \brief Allocate a block of memory of *size* elements
     * \param size The number of elements
     * \return A pointer to the allocated memory
     */
    template <typename T>
    static T* allocate(std::size_t size) {
        auto required_bytes = sizeof(T) * size;
        auto offset         = (A - 1) + sizeof(uintptr_t);
        auto orig           = malloc(required_bytes + offset);

        if (!orig) {
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    /*!
     * \brief Release the memory
     * \param ptr The pointer to the memory to be released
     */
    template <typename T>
    static void release(T* ptr) {
        //Note the const_cast is only to allow compilation
        free((reinterpret_cast<void**>(const_cast<std::remove_const_t<T>*>(ptr)))[-1]);
    }
};

/*!
 * \brief Allocate an array of the given size for the given type
 * \param size The number of elements
 * \return An unique pointer to the memory
 */
template <typename T>
auto allocate(std::size_t size) {
    return std::make_unique<T[]>(size);
}

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
T* aligned_allocate(std::size_t size) {
    return aligned_allocator<void, 32>::allocate<T>(size);
}

/*!
 * \brief Release some aligned memory
 * \param ptr The ptr to the aligned memory
 */
template <typename T>
void aligned_release(T* ptr) {
    return aligned_allocator<void, 32>::release<T>(ptr);
}

/*!
 * \brief RAII wrapper for allocated aligned memory
 */
template <typename T>
struct aligned_ptr {
    T* ptr; ///< The raw pointer

    /*!
     * \brief Build an aligned_ptr managing the given pointer
     */
    explicit aligned_ptr(T* ptr) : ptr(ptr) {}

    aligned_ptr(const aligned_ptr& rhs) = delete;
    aligned_ptr& operator=(const aligned_ptr& rhs) = delete;

    /*!
     * \brief Move construct an aligned_ptr
     * \param rhs The pointer to move
     */
    aligned_ptr(aligned_ptr&& rhs) : ptr(rhs.ptr) {
        rhs.ptr = nullptr;
    }

    /*!
     * \brief Move assign an aligned_ptr
     * \param rhs The pointer to move
     * \return the aligned_ptr
     */
    aligned_ptr& operator=(aligned_ptr&& rhs){
        if(this != &rhs){
            ptr = rhs.ptr;
            rhs.ptr = nullptr;
        }

        return *this;
    }

    /*!
     * \brief Returns a reference to the element at psition i
     */
    inline T& operator[](std::size_t i){
        return ptr[i];
    }

    /*!
     * \brief Returns a reference to the element at psition i
     */
    inline const T& operator[](std::size_t i) const {
        return ptr[i];
    }

    /*!
     * \brief Destruct the aligned_ptr and release the aligned memory
     */
    ~aligned_ptr(){
        if(ptr){
            aligned_release(ptr);
        }
    }

    /*!
     * \brief Returns the raw underlying pointer
     */
    T* get(){
        return ptr;
    }
};

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
aligned_ptr<T> aligned_allocate_auto(std::size_t size) {
    return aligned_ptr<T>{aligned_allocate<T>(size)};
}

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


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

#ifndef ETL_MMUL_EXPR_HPP
#define ETL_MMUL_EXPR_HPP

#include <algorithm>

#include "impl/mmul.hpp"

#include "traits_lite.hpp"

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 T, template<typename...> class Impl>
struct basic_mmul_expr {
    template<typename A, typename B, class Enable = void>
    struct result_type_builder {
        using type = dyn_matrix<value_t<A>>;
    };

    template<typename A, typename B>
    struct result_type_builder<A, B, std::enable_if_t<decay_traits<A>::is_fast && decay_traits<B>::is_fast>> {
        using type = fast_dyn_matrix<typename std::decay_t<A>::value_type, decay_traits<A>::template dim<0>(), decay_traits<B>::template dim<1>()>;
    };

    template<typename A, typename B>
    using result_type = typename result_type_builder<A, B>::type;

    template<typename A, typename B, cpp_enable_if(decay_traits<A>::is_fast && decay_traits<B>::is_fast)>
    static result_type<A,B>* allocate(A&&, B&&){
        return new result_type<A, B>();
    }

    template<typename A, typename B, cpp_disable_if(decay_traits<A>::is_fast && decay_traits<B>::is_fast)>
    static result_type<A,B>* allocate(A&& a, B&& b){
        return new result_type<A, B>(decay_traits<A>::dim(a, 0), decay_traits<B>::dim(b, 1));
    }

    template<typename A, typename B, typename C>
    static void apply(A&& a, 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(decay_traits<A>::dimensions() == 2 && decay_traits<B>::dimensions() == 2 && decay_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
        detail::check_mmul_sizes(a,b,c);

        Impl<A,B,C,void>::apply(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));
    }

    static std::string desc() noexcept {
        return "mmul";
    }

    template<typename A, typename B>
    static std::size_t size(const A& a, const B& b){
        return decay_traits<A>::dim(a, 0) * decay_traits<B>::dim(b, 1);
    }

    template<typename A, typename B>
    static std::size_t dim(const A& a, const B& b, std::size_t d){
        if(d == 0){
            return decay_traits<A>::dim(a, 0);
        } else {
            return decay_traits<B>::dim(b, 1);
        }
    }

    template<typename A, typename B>
    static constexpr std::size_t size(){
        return etl_traits<A>::template dim<0>() * etl_traits<B>::template dim<1>();
    }

    template<typename A, typename B, std::size_t D>
    static constexpr std::size_t dim(){
        return D == 0 ? etl_traits<A>::template dim<0>() : etl_traits<B>::template dim<1>();
    }

    static constexpr std::size_t dimensions(){
        return 2;
    }
};

template<typename T>
using mmul_expr = basic_mmul_expr<T, detail::mmul_impl>;

template<typename T>
using strassen_mmul_expr = basic_mmul_expr<T, detail::strassen_mmul_impl>;

} //end of namespace etl

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

#ifndef ETL_MMUL_EXPR_HPP
#define ETL_MMUL_EXPR_HPP

#include <algorithm>

#include "impl/mmul.hpp"

#include "traits_lite.hpp"

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 T, template<typename...> class Impl>
struct basic_mmul_expr {
    template<typename A, typename B, class Enable = void>
    struct result_type_builder {
        using type = dyn_matrix<value_t<A>>;
    };

    template<typename A, typename B>
    struct result_type_builder<A, B, std::enable_if_t<decay_traits<A>::is_fast && decay_traits<B>::is_fast>> {
        using type = fast_dyn_matrix<typename std::decay_t<A>::value_type, decay_traits<A>::template dim<0>(), decay_traits<B>::template dim<1>()>;
    };

    template<typename A, typename B>
    using result_type = typename result_type_builder<A, B>::type;

    template<typename A, typename B, cpp_enable_if(decay_traits<A>::is_fast && decay_traits<B>::is_fast)>
    static result_type<A,B>* allocate(A&&, B&&){
        return new result_type<A, B>();
    }

    template<typename A, typename B, cpp_disable_if(decay_traits<A>::is_fast && decay_traits<B>::is_fast)>
    static result_type<A,B>* allocate(A&& a, B&& b){
        return new result_type<A, B>(etl::dim<0>(a), etl::dim<1>(b));
    }

    template<typename A, typename B, typename C>
    static void apply(A&& a, 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(decay_traits<A>::dimensions() == 2 && decay_traits<B>::dimensions() == 2 && decay_traits<C>::dimensions() == 2, "Matrix multiplication only works in 2D");
        detail::check_mmul_sizes(a,b,c);

        Impl<A,B,C,void>::apply(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));
    }

    static std::string desc() noexcept {
        return "mmul";
    }

    template<typename A, typename B>
    static std::size_t size(const A& a, const B& b){
        return etl::dim<0>(a) * etl::dim<1>(b);
    }

    template<typename A, typename B>
    static std::size_t dim(const A& a, const B& b, std::size_t d){
        if(d == 0){
            return etl::dim<0>(a);
        } else {
            return etl::dim<1>(b);
        }
    }

    template<typename A, typename B>
    static constexpr std::size_t size(){
        return etl_traits<A>::template dim<0>() * etl_traits<B>::template dim<1>();
    }

    template<typename A, typename B, std::size_t D>
    static constexpr std::size_t dim(){
        return D == 0 ? etl_traits<A>::template dim<0>() : etl_traits<B>::template dim<1>();
    }

    static constexpr std::size_t dimensions(){
        return 2;
    }
};

template<typename T>
using mmul_expr = basic_mmul_expr<T, detail::mmul_impl>;

template<typename T>
using strassen_mmul_expr = basic_mmul_expr<T, detail::strassen_mmul_impl>;

} //end of namespace etl

#endif
<|endoftext|>


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

/*!
 * \file
 * \brief Contains forward declarations and using declarations for
 * the various value types.
 */

#pragma once

#include <cstddef>
#include "cpp_utils/array_wrapper.hpp"
#include "cpp_utils/aligned_vector.hpp"
#include "cpp_utils/aligned_array.hpp"

namespace etl {

template <typename T>
static constexpr size_t alloc_size_vec(size_t size) {
    return padding
        ? size + (size % default_intrinsic_traits<T>::size == 0 ? 0 : (default_intrinsic_traits<T>::size - (size % default_intrinsic_traits<T>::size)))
        : size;
}

#ifdef ETL_ADVANCED_PADDING

template <typename T>
static constexpr size_t alloc_size_mat(size_t size, size_t last) {
    return size == 0 ? 0 :
        (padding
        ? (size / last) * (last + (last % default_intrinsic_traits<T>::size == 0 ? 0 : (default_intrinsic_traits<T>::size - last % default_intrinsic_traits<T>::size)))
        : size);
}

#else

template <typename T>
static constexpr size_t alloc_size_mat(size_t size, size_t /*last*/) {
    return size == 0 ? 0 : alloc_size_vec<T>(size);
}

#endif

template <typename T, size_t... Dims>
static constexpr size_t alloc_size_mat() {
    return alloc_size_mat<T>(mul_all<Dims...>(), nth_size<sizeof...(Dims) - 1, 0, Dims...>::value);
}

template <typename T, typename ST, order SO, size_t... Dims>
struct fast_matrix_impl;

template <typename T, typename ST, order SO, size_t... Dims>
struct custom_fast_matrix_impl;

template <typename T, order SO, size_t D = 2>
struct dyn_matrix_impl;

template <typename T, order SO, size_t D = 2>
struct custom_dyn_matrix_impl;

template <typename T, sparse_storage SS, size_t D>
struct sparse_matrix_impl;

template <typename Stream>
struct serializer;

template <typename Stream>
struct deserializer;

/*!
 * \brief Symmetric matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct symmetric_matrix;

/*!
 * \brief Hermitian matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct hermitian_matrix;

/*!
 * \brief Diagonal matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct diagonal_matrix;

/*!
 * \brief Upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct upper_matrix;

/*!
 * \brief Strictly upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct strictly_upper_matrix;

/*!
 * \brief Uni upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct uni_upper_matrix;

/*!
 * \brief Lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct lower_matrix;

/*!
 * \brief Strictly lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct strictly_lower_matrix;

/*!
 * \brief Uni lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct uni_lower_matrix;

/*!
 * \brief A static matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using fast_matrix = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_mat<T, Dims...>(), default_intrinsic_traits<T>::alignment>, order::RowMajor, Dims...>;

/*!
 * \brief A static matrix with fixed dimensions, in column-major order
 */
template <typename T, size_t... Dims>
using fast_matrix_cm = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_mat<T, Dims...>(), default_intrinsic_traits<T>::alignment>, order::ColumnMajor, Dims...>;

/*!
 * \brief A static vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using fast_vector = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_vec<T>(Rows), default_intrinsic_traits<T>::alignment>, order::RowMajor, Rows>;

/*!
 * \brief A static vector with fixed dimensions, in column-major order
 */
template <typename T, size_t Rows>
using fast_vector_cm = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_vec<T>(Rows), default_intrinsic_traits<T>::alignment>, order::ColumnMajor, Rows>;

/*!
 * \brief A hybrid vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using fast_dyn_vector = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, order::RowMajor, Rows>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using fast_dyn_matrix = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, order::RowMajor, Dims...>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in specified  order
 */
template <typename T, order SO, size_t... Dims>
using fast_dyn_matrix_o = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, SO, Dims...>;

/*!
 * \brief A dynamic matrix, in row-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using dyn_matrix = dyn_matrix_impl<T, order::RowMajor, D>;

/*!
 * \brief A dynamic matrix, in column-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using dyn_matrix_cm = dyn_matrix_impl<T, order::ColumnMajor, D>;

/*!
 * \brief A dynamic matrix, in specific storage order, of D dimensions
 */
template <typename T, order SO, size_t D = 2>
using dyn_matrix_o = dyn_matrix_impl<T, SO, D>;

/*!
 * \brief A dynamic vector, in row-major order
 */
template <typename T>
using dyn_vector = dyn_matrix_impl<T, order::RowMajor, 1>;

/*!
 * \brief A dynamic matrix, in row-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using custom_dyn_matrix                    = custom_dyn_matrix_impl<T, order::RowMajor, D>;

/*!
 * \brief A dynamic matrix, in column-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using custom_dyn_matrix_cm                 = custom_dyn_matrix_impl<T, order::ColumnMajor, D>;

/*!
 * \brief A dynamic vector, in row-major order
 */
template <typename T>
using custom_dyn_vector = custom_dyn_matrix_impl<T, order::RowMajor, 1>;

/*!
 * \brief A hybrid vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using custom_fast_vector = custom_fast_matrix_impl<T, cpp::array_wrapper<T>, order::RowMajor, Rows>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using custom_fast_matrix = custom_fast_matrix_impl<T, cpp::array_wrapper<T>, order::RowMajor, Dims...>;

/*!
 * \brief A sparse matrix, of D dimensions
 */
template <typename T, size_t D = 2>
using sparse_matrix                 = sparse_matrix_impl<T, sparse_storage::COO, D>;

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

/*!
 * \file
 * \brief Contains forward declarations and using declarations for
 * the various value types.
 */

#pragma once

#include <cstddef>
#include "cpp_utils/array_wrapper.hpp"
#include "cpp_utils/aligned_vector.hpp"
#include "cpp_utils/aligned_array.hpp"

namespace etl {

/*!
 * \brief Compute the real size to allocate for a vector of the
 * given size and type
 * \param size The number of elements of the vector
 * \tparam T The type contained in the vector
 * \return The size to be allocated
 */
template <typename T>
static constexpr size_t alloc_size_vec(size_t size) {
    return padding
        ? size + (size % default_intrinsic_traits<T>::size == 0 ? 0 : (default_intrinsic_traits<T>::size - (size % default_intrinsic_traits<T>::size)))
        : size;
}

#ifdef ETL_ADVANCED_PADDING

/*!
 * \brief Compute the real allocated size for a 2D matrix
 * \tparam T the type of the elements of the matrix
 * \param size The size of the matrix
 * \param last The last dimension of the matrix
 * \return the allocated size for the matrix
 */
template <typename T>
static constexpr size_t alloc_size_mat(size_t size, size_t last) {
    return size == 0 ? 0 :
        (padding
        ? (size / last) * (last + (last % default_intrinsic_traits<T>::size == 0 ? 0 : (default_intrinsic_traits<T>::size - last % default_intrinsic_traits<T>::size)))
        : size);
}

#else

/*!
 * \brief Compute the real allocated size for a 2D matrix
 * \tparam T the type of the elements of the matrix
 * \param size The size of the matrix
 * \param last The last dimension of the matrix
 * \return the allocated size for the matrix
 */
template <typename T>
static constexpr size_t alloc_size_mat(size_t size, size_t last) {
    cpp_unused(last);
    return size == 0 ? 0 : alloc_size_vec<T>(size);
}

#endif

/*!
 * \brief Compute the real allocated size for a matrix
 * \tparam T the type of the elements of the matrix
 * \tparam Dims The dimensions of the matrix
 * \return the allocated size for the matrix
 */
template <typename T, size_t... Dims>
static constexpr size_t alloc_size_mat() {
    return alloc_size_mat<T>(mul_all<Dims...>(), nth_size<sizeof...(Dims) - 1, 0, Dims...>::value);
}

template <typename T, typename ST, order SO, size_t... Dims>
struct fast_matrix_impl;

template <typename T, typename ST, order SO, size_t... Dims>
struct custom_fast_matrix_impl;

template <typename T, order SO, size_t D = 2>
struct dyn_matrix_impl;

template <typename T, order SO, size_t D = 2>
struct custom_dyn_matrix_impl;

template <typename T, sparse_storage SS, size_t D>
struct sparse_matrix_impl;

template <typename Stream>
struct serializer;

template <typename Stream>
struct deserializer;

/*!
 * \brief Symmetric matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct symmetric_matrix;

/*!
 * \brief Hermitian matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct hermitian_matrix;

/*!
 * \brief Diagonal matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct diagonal_matrix;

/*!
 * \brief Upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct upper_matrix;

/*!
 * \brief Strictly upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct strictly_upper_matrix;

/*!
 * \brief Uni upper triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct uni_upper_matrix;

/*!
 * \brief Lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct lower_matrix;

/*!
 * \brief Strictly lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct strictly_lower_matrix;

/*!
 * \brief Uni lower triangular matrix adapter
 * \tparam Matrix The adapted matrix
 */
template <typename Matrix>
struct uni_lower_matrix;

/*!
 * \brief A static matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using fast_matrix = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_mat<T, Dims...>(), default_intrinsic_traits<T>::alignment>, order::RowMajor, Dims...>;

/*!
 * \brief A static matrix with fixed dimensions, in column-major order
 */
template <typename T, size_t... Dims>
using fast_matrix_cm = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_mat<T, Dims...>(), default_intrinsic_traits<T>::alignment>, order::ColumnMajor, Dims...>;

/*!
 * \brief A static vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using fast_vector = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_vec<T>(Rows), default_intrinsic_traits<T>::alignment>, order::RowMajor, Rows>;

/*!
 * \brief A static vector with fixed dimensions, in column-major order
 */
template <typename T, size_t Rows>
using fast_vector_cm = fast_matrix_impl<T, cpp::aligned_array<T, alloc_size_vec<T>(Rows), default_intrinsic_traits<T>::alignment>, order::ColumnMajor, Rows>;

/*!
 * \brief A hybrid vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using fast_dyn_vector = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, order::RowMajor, Rows>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using fast_dyn_matrix = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, order::RowMajor, Dims...>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in specified  order
 */
template <typename T, order SO, size_t... Dims>
using fast_dyn_matrix_o = fast_matrix_impl<T, cpp::aligned_vector<T, default_intrinsic_traits<T>::alignment>, SO, Dims...>;

/*!
 * \brief A dynamic matrix, in row-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using dyn_matrix = dyn_matrix_impl<T, order::RowMajor, D>;

/*!
 * \brief A dynamic matrix, in column-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using dyn_matrix_cm = dyn_matrix_impl<T, order::ColumnMajor, D>;

/*!
 * \brief A dynamic matrix, in specific storage order, of D dimensions
 */
template <typename T, order SO, size_t D = 2>
using dyn_matrix_o = dyn_matrix_impl<T, SO, D>;

/*!
 * \brief A dynamic vector, in row-major order
 */
template <typename T>
using dyn_vector = dyn_matrix_impl<T, order::RowMajor, 1>;

/*!
 * \brief A dynamic matrix, in row-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using custom_dyn_matrix                    = custom_dyn_matrix_impl<T, order::RowMajor, D>;

/*!
 * \brief A dynamic matrix, in column-major order, of D dimensions
 */
template <typename T, size_t D = 2>
using custom_dyn_matrix_cm                 = custom_dyn_matrix_impl<T, order::ColumnMajor, D>;

/*!
 * \brief A dynamic vector, in row-major order
 */
template <typename T>
using custom_dyn_vector = custom_dyn_matrix_impl<T, order::RowMajor, 1>;

/*!
 * \brief A hybrid vector with fixed dimensions, in row-major order
 */
template <typename T, size_t Rows>
using custom_fast_vector = custom_fast_matrix_impl<T, cpp::array_wrapper<T>, order::RowMajor, Rows>;

/*!
 * \brief A hybrid matrix with fixed dimensions, in row-major order
 */
template <typename T, size_t... Dims>
using custom_fast_matrix = custom_fast_matrix_impl<T, cpp::array_wrapper<T>, order::RowMajor, Dims...>;

/*!
 * \brief A sparse matrix, of D dimensions
 */
template <typename T, size_t D = 2>
using sparse_matrix                 = sparse_matrix_impl<T, sparse_storage::COO, D>;

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


<commit_before>#ifndef CTHREADRINGBUF
#define CTHREADRINGBUF
#include<atomic>
#include<memory>	//allocator
#include<vector>
#include<utility>	//forward, move
#include"CSemaphore.hpp"
#include"../algorithm/algorithm.hpp"	//for_each_val
#include"../tool/CScopeGuard.hpp"

namespace nThread
{
	//a fixed-sized and cannot overwrite when buffer is full
	//T must meet the requirements of MoveAssignable and MoveConstructible
	template<class T>
	class CThreadRingBuf
	{
	public:
		using allocator_type=std::allocator<T>;
		using size_type=typename std::allocator<T>::size_type;
		using value_type=T;
	private:
		using pointer=typename std::allocator<T>::pointer;
		static allocator_type alloc_;
		const pointer begin_;
		std::vector<std::atomic<bool>> complete_;
		std::atomic<size_type> read_subscript_;
		CSemaphore sema_;
		size_type size_;
		std::atomic<size_type> use_construct_;
		std::atomic<size_type> write_subscript_;
		//can only be used when your write will not overwrite the data
		template<class TFwdRef>
		void write_(TFwdRef &&val)
		{
			sema_.signal();
			const auto write{write_subscript_++};
			while(complete_[write%size()].load(std::memory_order_acquire))
				;
			if(write<size()&&use_construct_++<size())
				alloc_.construct(begin_+write,std::forward<TFwdRef>(val));
			else
				begin_[write%size()]=std::forward<TFwdRef>(val);
			complete_[write%size()].store(true,std::memory_order_release);
		}
	public:
		explicit CThreadRingBuf(const size_type size)
			:begin_{alloc_.allocate(size)},complete_(size),size_{size}{}
		inline size_type available() const noexcept
		{
			return static_cast<size_type>(sema_.count());
		}
		value_type read()
		{
			sema_.wait();
			const auto read{(read_subscript_++)%size()};
			while(!complete_[read].load(std::memory_order_acquire))
				;
			nTool::CScopeGuard sg{[&]{complete_[read].store(false,std::memory_order_release);}};
			return std::move(begin_[read]);
		}
		inline size_type size() const noexcept
		{
			return size_;
		}
		inline void write(const T &val)
		{
			write_(val);
		}
		inline void write(T &&val)
		{
			write_(std::move(val));
		}
		~CThreadRingBuf()
		{
			nAlgorithm::for_each_val(begin_,begin_+size(),[&](const auto p){alloc_.destroy(p);});
			alloc_.deallocate(begin_,size());
		}
	};

	template<class T>
	typename CThreadRingBuf<T>::allocator_type CThreadRingBuf<T>::alloc_;
}

#endif<commit_msg>replace move to move_if_noexcept<commit_after>#ifndef CTHREADRINGBUF
#define CTHREADRINGBUF
#include<atomic>
#include<memory>	//allocator
#include<vector>
#include<utility>	//forward, move, move_if_noexcept
#include"CSemaphore.hpp"
#include"../algorithm/algorithm.hpp"	//for_each_val
#include"../tool/CScopeGuard.hpp"

namespace nThread
{
	//a fixed-sized and cannot overwrite when buffer is full
	template<class T>
	class CThreadRingBuf
	{
	public:
		using allocator_type=std::allocator<T>;
		using size_type=typename std::allocator<T>::size_type;
		using value_type=T;
	private:
		using pointer=typename std::allocator<T>::pointer;
		static allocator_type alloc_;
		const pointer begin_;
		std::vector<std::atomic<bool>> complete_;
		std::atomic<size_type> read_subscript_;
		CSemaphore sema_;
		size_type size_;
		std::atomic<size_type> use_construct_;
		std::atomic<size_type> write_subscript_;
		//can only be used when your write will not overwrite the data
		template<class TFwdRef>
		void write_(TFwdRef &&val)
		{
			sema_.signal();
			const auto write{write_subscript_++};
			while(complete_[write%size()].load(std::memory_order_acquire))
				;
			if(write<size()&&use_construct_++<size())
				alloc_.construct(begin_+write,std::forward<TFwdRef>(val));
			else
				begin_[write%size()]=std::forward<TFwdRef>(val);
			complete_[write%size()].store(true,std::memory_order_release);
		}
	public:
		explicit CThreadRingBuf(const size_type size)
			:begin_{alloc_.allocate(size)},complete_(size),size_{size}{}
		inline size_type available() const noexcept
		{
			return static_cast<size_type>(sema_.count());
		}
		value_type read()
		{
			sema_.wait();
			const auto read{(read_subscript_++)%size()};
			while(!complete_[read].load(std::memory_order_acquire))
				;
			nTool::CScopeGuard sg{[&]{complete_[read].store(false,std::memory_order_release);}};
			return std::move_if_noexcept(begin_[read]);
		}
		inline size_type size() const noexcept
		{
			return size_;
		}
		inline void write(const T &val)
		{
			write_(val);
		}
		inline void write(T &&val)
		{
			write_(std::move(val));
		}
		~CThreadRingBuf()
		{
			nAlgorithm::for_each_val(begin_,begin_+size(),[&](const auto p){alloc_.destroy(p);});
			alloc_.deallocate(begin_,size());
		}
	};

	template<class T>
	typename CThreadRingBuf<T>::allocator_type CThreadRingBuf<T>::alloc_;
}

#endif<|endoftext|>


<commit_before>/** \file jsonv/forward.hpp
 *
 *  Copyright (c) 2012-2014 by Travis Gockel. All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
 *  as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
 *  version.
 *
 *  \author Travis Gockel (travis@gockelhut.com)
**/
#ifndef __JSONV_FORWARD_HPP_INCLUDED__
#define __JSONV_FORWARD_HPP_INCLUDED__

namespace jsonv
{

class encoder;
enum class kind : unsigned char;
class kind_error;
class parse_error;
class parse_options;
class path;
class path_element;
enum class path_element_kind : unsigned char;
class tokenizer;
enum class token_kind : unsigned int;
class value;
struct version;

}

#endif/*__JSONV_FORWARD_HPP_INCLUDED__*/
<commit_msg>Adds serialization classes to forwards.<commit_after>/** \file jsonv/forward.hpp
 *
 *  Copyright (c) 2012-2014 by Travis Gockel. All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
 *  as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
 *  version.
 *
 *  \author Travis Gockel (travis@gockelhut.com)
**/
#ifndef __JSONV_FORWARD_HPP_INCLUDED__
#define __JSONV_FORWARD_HPP_INCLUDED__

namespace jsonv
{

class adapter;
class encoder;
class extractor;
class extraction_context;
class formats;
enum class kind : unsigned char;
class kind_error;
class parse_error;
class parse_options;
class path;
class path_element;
enum class path_element_kind : unsigned char;
class serializer;
class serialization_context;
class tokenizer;
enum class token_kind : unsigned int;
class value;
struct version;

}

#endif/*__JSONV_FORWARD_HPP_INCLUDED__*/
<|endoftext|>


<commit_before>/*! \file kernel/userver.hh
 *******************************************************************************

 File: userver.h\n
 Definition of the USystem class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2005.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 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.

 For more information, comments, bug reports: http://www.urbiforge.net

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

#ifndef KERNEL_USERVER_HH
# define KERNEL_USERVER_HH

# include <cstdarg>
# include <sstream>

# include <libport/config.h>
# if ! defined LIBPORT_URBI_ENV_AIBO
#  include <boost/thread.hpp>
# endif

# include <libport/fwd.hh>
# include <libport/compiler.hh>
# include <libport/file-library.hh>
# include <libport/ufloat.h>
# include <libport/utime.hh>

# include "kernel/fwd.hh"
# include "kernel/utypes.hh"

namespace runner
{
  class Runner;
}

namespace scheduler
{
  class Scheduler;
}

extern const char* DISPLAY_FORMAT;
extern const char* DISPLAY_FORMAT1;
extern const char* DISPLAY_FORMAT2;

/// Global variable for the server
extern class UServer* urbiserver;

//! UServer class: handles all URBI system processing.
/*! There must be one UServer defined in the program and it must be overloaded
    to make it specific to the particular robot.

    UServer is used to store the UConnection list and the UDevice list.
    This object does all the internal processing of URBI and handles the pool
    of UCommand's.
*/
class UServer
{
public:
  UServer(const char* mainName);
  virtual ~UServer ();

public:
  //! Initialization of the server. Displays the header message & init stuff
  /*! This function must be called once the server is operational and
   able to print messages. It is a requirement for URBI compliance to print
   the header at start, so this function *must* be called. Beside, it also
   do initalization work for the devices and system variables.
   */
  void initialize ();

  /// Process the jobs.
  /// \return the time when should be called again.
  libport::utime_t work ();

  /// Set the system.args list in URBI.
  void main (int argc, const char* argv[]);

  /// Package information about this server.
  static const libport::PackageInfo& package_info ();

  //! Displays a formatted error message.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   It formats the output in a standard URBI way by adding an ERROR key
   between brackets at the end.
   */
  void error (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Displays a formatted message.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   It formats the output in a standard URBI way by adding an empty key
   between brackets at the end. If you want to specify a key, use the
   echoKey() function.
   \param s is the formatted string containing the message.
   \sa echoKey()
   */
  void echo (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Display a formatted message, with a key.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.
   It formats the output in a standard URBI way by adding a key between
   brackets at the end. This key can be "" or NULL.It can be used to
   visually extract information from the flux of messages printed by
   the server.
   \param key is the message key. Maxlength = 5 chars.
   \param s   is the formatted string containing the message.
   \param args Arguments for the format string.
   */
  void vecho_key (const char* key, const char* s, va_list args)
    __attribute__ ((__format__ (__printf__, 3, 0)));
  void echoKey (const char* key, const char* s, ...)
    __attribute__ ((__format__ (__printf__, 3, 4)));

  /// Send debugging data.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   \param s is the formatted string containing the message
   \param args Arguments for the format string.
   */
  void vdebug (const char* s, va_list args)
    __attribute__ ((__format__ (__printf__, 2, 0)));
  void debug (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Overload this function to return the running time of the server.
  /*! The running time of the server must be in milliseconds.
   */
  virtual libport::utime_t getTime () = 0;

  //! Overload this function to return the remaining power of the robot
  /*! The remaining power is expressed as percentage. 0 for empty batteries
   and 1 for full power.
   */
  virtual ufloat getPower () = 0;

  //! Overload this function to return a specific header for your URBI server
  /*! Used to give some information specific to your server in the standardized
   header which is displayed on the server output at start and in the
   connection when a new connection is created.\n
   Typical custom header should be like:

   *** URBI version xx.xx for \<robotname\> robot\\n\n
   *** (c) Copyright \<year\> \<name\>\\n

   The function should return in header the line corresponding to 'line'
   or an empty string (not NULL!) when there is no line any more.
   Each line is supposed to end with a carriage return \\n and each line should
   start with three empty spaces. This complicated method is necessary to allow
   the connection to stamp every line with the standard URBI prefix [time:tag].

   \param line is the requested line number
   \param header the custom header
   \param maxlength the maximum length allowed for the header (the parameter
   has been malloc'ed for that size). Typical size is 1024 octets and
   should be enough for any reasonable header.
   */
  virtual void      getCustomHeader (int line, char* header,
				     int maxlength) = 0;

  /// Path to explore when looking for .u files.
  libport::file_library search_path;

  /// Return the full file name, handle paths.
  /// Return \a f on failure.
  virtual std::string find_file (const libport::path& path);

  /// Type of UCommandQueue
  enum QueueType {
    /// The UComandQueue contains URBI code.
    QUEUE_URBI,
    /// THe UCommandQueu contains data, not to be messed with.
    QUEUE_DATA
  };

  /// Load a file into the connection.
  /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
  virtual UErrorValue loadFile (const std::string& file_name,
				UQueue& loadQueue,
				QueueType t=QUEUE_URBI);

  /// Load \a fn in the ghostqueue.
  UErrorValue load_init_file(const char* fn);

  /// Save content to a file
  /// This function must be redefined by the robot-specific server.
  /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
  virtual UErrorValue saveFile (const std::string& filename,
				const std::string& content) = 0;

  void mark (UString* stopTag);

  //! Overload this function to specify how your system will reboot
  virtual void reboot () = 0;

  //! Overload this function to specify how your system will shutdown
  virtual void shutdown ();

  //! Function called before work
  /*! Redefine this virtual function if you need to do pre-processing before
    the work function starts.
  */
  virtual void beforeWork ();

  //! Function called after work
  /*! Redefine this virtual function if you need to do post-processing
    before the work function ends.
  */
  virtual void afterWork ();

  /// Display a message on the robot console.
  void display (const char*);
  /// Display a set of messages on the robot console.
  void display (const char**);

  //! Accessor for lastTime_.
  libport::utime_t lastTime ();

  //! Update lastTime_ to current time.
  //! Update the server's time using the robot-specific implementation
  /*! It is necessary to have an update of the server time to
   increase the performance of successive calls to getTime.
   It allows also to see a whole processing session (like the
   processing of the command tree) as occuring AT the same time,
   from the server's point of view.
   */
  void updateTime ();

  /*--------------.
  | Connections.  |
  `--------------*/

  /// Add a new connection to the connection list.
  /// Take ownership on c. Also perform some error testing on the connection
  /// value and UError return code
  /// \precondition c != 0
  void connection_add(UConnection* c);

  /// Remove from the connection list.
  /// This function perform also some error testing on the connection
  /// value and UError return code
  /// Destroy \a c.
  void connection_remove(UConnection* c);

  // A usual connection to stop dependencies.
  UConnection& getGhostConnection();

  /*--------------------.
  | Scheduler, runner.  |
  `--------------------*/
public:
  const scheduler::Scheduler& getScheduler () const;
  scheduler::Scheduler& getScheduler ();

  runner::Runner& getCurrentRunner () const;

protected:
  //! Overload this function to specify how your robot is displaying messages.
  virtual void effectiveDisplay (const char*) = 0;

private:
  // Pointer to stop the header dependency.
  scheduler::Scheduler* scheduler_;

private:
  /// \{ Various parts of @c UServer::work.
  /// Scan currently opened connections for ongoing work
  void work_handle_connections_ ();
  /// Scan currently opened connections for deleting marked commands or
  /// killall order
  void work_handle_stopall_ ();
  void work_test_cpuoverload_ ();
  /// \}

public:
  /// Shows debug or not.
  bool debugOutput;

# if ! defined LIBPORT_URBI_ENV_AIBO
  /// Used to synchronize message reception.
  boost::recursive_mutex mutex;
# endif

private:
  /// Name of the main device.
  std::string mainName_;

public:
  /// Stops all commands in all connections.
  bool stopall;

  enum
  {
    /// Urbi TCP Port.
    TCP_PORT = 54000,
    /// Used by echo() & error().
    // FIXME: Because of this stupid hard limit, we can't produce
    // large outputs!  We should move to using C++.  Or some scheme
    // that is robust to the size of the message.
    MAXSIZE_INTERNALMESSAGE = 8192,
  };

private:
  /// Store the time on the last call to updateTime().
  libport::utime_t lastTime_;

  /// List of active connections: includes one UGhostConnection.
  // FIXME: This is meant to become a runner::Job and move out of this class.
  std::list<UConnection*> connections_;

  /// The ghost connection used for URBI.INI.
  UGhostConnection* ghost_;
};

/*-------------------------.
| Freestanding functions.  |
`-------------------------*/

/// Send debugging messages via ::urbiserver.
void vdebug (const char* fmt, va_list args)
  __attribute__ ((__format__ (__printf__, 1, 0)));

/// Send debugging messages via ::urbiserver.
void debug (const char* fmt, ...)
  __attribute__ ((__format__ (__printf__, 1, 2)));

// Send debugging messages.
# if URBI_DEBUG
// Must be invoked with two pairs of parens.
#  define DEBUG(Msg)  debug Msg
# else
#  define DEBUG(Msg) ((void) 0)
# endif

# include <kernel/userver.hxx>

#endif // !KERNEL_USERVER_HH
<commit_msg>Do not repeat what is in fwd.hh<commit_after>/*! \file kernel/userver.hh
 *******************************************************************************

 File: userver.h\n
 Definition of the USystem class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2005.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 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.

 For more information, comments, bug reports: http://www.urbiforge.net

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

#ifndef KERNEL_USERVER_HH
# define KERNEL_USERVER_HH

# include <cstdarg>
# include <sstream>

# include <libport/config.h>
# if ! defined LIBPORT_URBI_ENV_AIBO
#  include <boost/thread.hpp>
# endif

# include <libport/fwd.hh>
# include <libport/compiler.hh>
# include <libport/file-library.hh>
# include <libport/ufloat.h>
# include <libport/utime.hh>

# include "kernel/fwd.hh"
# include "kernel/utypes.hh"

# include "runner/fwd.hh"
# include "scheduler/fwd.hh"

extern const char* DISPLAY_FORMAT;
extern const char* DISPLAY_FORMAT1;
extern const char* DISPLAY_FORMAT2;

/// Global variable for the server
extern class UServer* urbiserver;

//! UServer class: handles all URBI system processing.
/*! There must be one UServer defined in the program and it must be overloaded
    to make it specific to the particular robot.

    UServer is used to store the UConnection list and the UDevice list.
    This object does all the internal processing of URBI and handles the pool
    of UCommand's.
*/
class UServer
{
public:
  UServer(const char* mainName);
  virtual ~UServer ();

public:
  //! Initialization of the server. Displays the header message & init stuff
  /*! This function must be called once the server is operational and
   able to print messages. It is a requirement for URBI compliance to print
   the header at start, so this function *must* be called. Beside, it also
   do initalization work for the devices and system variables.
   */
  void initialize ();

  /// Process the jobs.
  /// \return the time when should be called again.
  libport::utime_t work ();

  /// Set the system.args list in URBI.
  void main (int argc, const char* argv[]);

  /// Package information about this server.
  static const libport::PackageInfo& package_info ();

  //! Displays a formatted error message.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   It formats the output in a standard URBI way by adding an ERROR key
   between brackets at the end.
   */
  void error (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Displays a formatted message.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   It formats the output in a standard URBI way by adding an empty key
   between brackets at the end. If you want to specify a key, use the
   echoKey() function.
   \param s is the formatted string containing the message.
   \sa echoKey()
   */
  void echo (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Display a formatted message, with a key.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.
   It formats the output in a standard URBI way by adding a key between
   brackets at the end. This key can be "" or NULL.It can be used to
   visually extract information from the flux of messages printed by
   the server.
   \param key is the message key. Maxlength = 5 chars.
   \param s   is the formatted string containing the message.
   \param args Arguments for the format string.
   */
  void vecho_key (const char* key, const char* s, va_list args)
    __attribute__ ((__format__ (__printf__, 3, 0)));
  void echoKey (const char* key, const char* s, ...)
    __attribute__ ((__format__ (__printf__, 3, 4)));

  /// Send debugging data.
  /*! This function uses the virtual URobot::display() function to make the
   message printing robot-specific.

   \param s is the formatted string containing the message
   \param args Arguments for the format string.
   */
  void vdebug (const char* s, va_list args)
    __attribute__ ((__format__ (__printf__, 2, 0)));
  void debug (const char* s, ...)
    __attribute__ ((__format__ (__printf__, 2, 3)));

  //! Overload this function to return the running time of the server.
  /*! The running time of the server must be in milliseconds.
   */
  virtual libport::utime_t getTime () = 0;

  //! Overload this function to return the remaining power of the robot
  /*! The remaining power is expressed as percentage. 0 for empty batteries
   and 1 for full power.
   */
  virtual ufloat getPower () = 0;

  //! Overload this function to return a specific header for your URBI server
  /*! Used to give some information specific to your server in the standardized
   header which is displayed on the server output at start and in the
   connection when a new connection is created.\n
   Typical custom header should be like:

   *** URBI version xx.xx for \<robotname\> robot\\n\n
   *** (c) Copyright \<year\> \<name\>\\n

   The function should return in header the line corresponding to 'line'
   or an empty string (not NULL!) when there is no line any more.
   Each line is supposed to end with a carriage return \\n and each line should
   start with three empty spaces. This complicated method is necessary to allow
   the connection to stamp every line with the standard URBI prefix [time:tag].

   \param line is the requested line number
   \param header the custom header
   \param maxlength the maximum length allowed for the header (the parameter
   has been malloc'ed for that size). Typical size is 1024 octets and
   should be enough for any reasonable header.
   */
  virtual void      getCustomHeader (int line, char* header,
				     int maxlength) = 0;

  /// Path to explore when looking for .u files.
  libport::file_library search_path;

  /// Return the full file name, handle paths.
  /// Return \a f on failure.
  virtual std::string find_file (const libport::path& path);

  /// Type of UCommandQueue
  enum QueueType {
    /// The UComandQueue contains URBI code.
    QUEUE_URBI,
    /// THe UCommandQueu contains data, not to be messed with.
    QUEUE_DATA
  };

  /// Load a file into the connection.
  /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
  virtual UErrorValue loadFile (const std::string& file_name,
				UQueue& loadQueue,
				QueueType t=QUEUE_URBI);

  /// Load \a fn in the ghostqueue.
  UErrorValue load_init_file(const char* fn);

  /// Save content to a file
  /// This function must be redefined by the robot-specific server.
  /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
  virtual UErrorValue saveFile (const std::string& filename,
				const std::string& content) = 0;

  void mark (UString* stopTag);

  //! Overload this function to specify how your system will reboot
  virtual void reboot () = 0;

  //! Overload this function to specify how your system will shutdown
  virtual void shutdown ();

  //! Function called before work
  /*! Redefine this virtual function if you need to do pre-processing before
    the work function starts.
  */
  virtual void beforeWork ();

  //! Function called after work
  /*! Redefine this virtual function if you need to do post-processing
    before the work function ends.
  */
  virtual void afterWork ();

  /// Display a message on the robot console.
  void display (const char*);
  /// Display a set of messages on the robot console.
  void display (const char**);

  //! Accessor for lastTime_.
  libport::utime_t lastTime ();

  //! Update lastTime_ to current time.
  //! Update the server's time using the robot-specific implementation
  /*! It is necessary to have an update of the server time to
   increase the performance of successive calls to getTime.
   It allows also to see a whole processing session (like the
   processing of the command tree) as occuring AT the same time,
   from the server's point of view.
   */
  void updateTime ();

  /*--------------.
  | Connections.  |
  `--------------*/

  /// Add a new connection to the connection list.
  /// Take ownership on c. Also perform some error testing on the connection
  /// value and UError return code
  /// \precondition c != 0
  void connection_add(UConnection* c);

  /// Remove from the connection list.
  /// This function perform also some error testing on the connection
  /// value and UError return code
  /// Destroy \a c.
  void connection_remove(UConnection* c);

  // A usual connection to stop dependencies.
  UConnection& getGhostConnection();

  /*--------------------.
  | Scheduler, runner.  |
  `--------------------*/
public:
  const scheduler::Scheduler& getScheduler () const;
  scheduler::Scheduler& getScheduler ();

  runner::Runner& getCurrentRunner () const;

protected:
  //! Overload this function to specify how your robot is displaying messages.
  virtual void effectiveDisplay (const char*) = 0;

private:
  // Pointer to stop the header dependency.
  scheduler::Scheduler* scheduler_;

private:
  /// \{ Various parts of @c UServer::work.
  /// Scan currently opened connections for ongoing work
  void work_handle_connections_ ();
  /// Scan currently opened connections for deleting marked commands or
  /// killall order
  void work_handle_stopall_ ();
  void work_test_cpuoverload_ ();
  /// \}

public:
  /// Shows debug or not.
  bool debugOutput;

# if ! defined LIBPORT_URBI_ENV_AIBO
  /// Used to synchronize message reception.
  boost::recursive_mutex mutex;
# endif

private:
  /// Name of the main device.
  std::string mainName_;

public:
  /// Stops all commands in all connections.
  bool stopall;

  enum
  {
    /// Urbi TCP Port.
    TCP_PORT = 54000,
    /// Used by echo() & error().
    // FIXME: Because of this stupid hard limit, we can't produce
    // large outputs!  We should move to using C++.  Or some scheme
    // that is robust to the size of the message.
    MAXSIZE_INTERNALMESSAGE = 8192,
  };

private:
  /// Store the time on the last call to updateTime().
  libport::utime_t lastTime_;

  /// List of active connections: includes one UGhostConnection.
  // FIXME: This is meant to become a runner::Job and move out of this class.
  std::list<UConnection*> connections_;

  /// The ghost connection used for URBI.INI.
  UGhostConnection* ghost_;
};

/*-------------------------.
| Freestanding functions.  |
`-------------------------*/

/// Send debugging messages via ::urbiserver.
void vdebug (const char* fmt, va_list args)
  __attribute__ ((__format__ (__printf__, 1, 0)));

/// Send debugging messages via ::urbiserver.
void debug (const char* fmt, ...)
  __attribute__ ((__format__ (__printf__, 1, 2)));

// Send debugging messages.
# if URBI_DEBUG
// Must be invoked with two pairs of parens.
#  define DEBUG(Msg)  debug Msg
# else
#  define DEBUG(Msg) ((void) 0)
# endif

# include <kernel/userver.hxx>

#endif // !KERNEL_USERVER_HH
<|endoftext|>


<commit_before>/// \file libport/ufloat.hh
/// \brief Definition of the ufloat classes.

#ifndef LIBPORT_UFLOAT_HH
# define LIBPORT_UFLOAT_HH

# include <libport/config.h>

# include <float.h>
# include <exception>

/*-----------------.
| Ufloat support.  |
`-----------------*/

# ifdef LIBPORT_URBI_UFLOAT_FLOAT
namespace libport
{
  typedef float ufloat;
#  define UFLT_EPSILON FLT_EPSILON

  inline long long to_long_long (ufloat u);
}
# endif

# ifdef LIBPORT_URBI_UFLOAT_DOUBLE
namespace libport
{
  typedef double ufloat;
#  define UFLT_EPSILON DBL_EPSILON

  inline long long to_long_long (ufloat u);
}
# endif

# ifdef LIBPORT_URBI_UFLOAT_LONG
#  include <libport/ulong-fixed-point.hh>
# endif

# ifdef LIBPORT_URBI_UFLOAT_LONG_LONG
#  include <libport/ull-fixed-point.hh>
# endif

# ifdef LIBPORT_URBI_UFLOAT_FLOATING
#  include <libport/uffloat.hh>
# endif

namespace libport
{
  static const ufloat PI(3.14159265358979323846264338327950288);
  static const ufloat UINFINITY(999999999999999.0);
}

/*-------------------.
| Ufloat tabulated.  |
`-------------------*/

# ifdef LIBPORT_URBI_UFLOAT_TABULATED
namespace libport
{
  /** @return the tabulated sinus of given @a angle in radian, using linear
   * interpolation.  */
  ufloat tabulatedSin(ufloat angle);

  /** @return the tabulated cosinus of given @a angle in radian, using linear
   * interpolation.  */
  ufloat tabulatedCos(ufloat angle);

  /** @return the tabulated arcsinus of given @a angle, in radian, using
   * linear interpolation.  */
  ufloat tabulatedASin(ufloat angle);

  /** @return the tabulated arccosinus of given @a angle, in radian, using
   * linear interpolation.  */
  inline ufloat tabulatedACos(ufloat angle);

  inline ufloat sin(ufloat angle);
  inline ufloat cos(ufloat angle);
  inline ufloat tan(ufloat angle);

  inline ufloat asin(ufloat angle);
  inline ufloat acos(ufloat angle);
}
# endif

# include <libport/config.h>
/* round is not C++ standard (not even POSIX) and neither gnulib nor Boost
 * provide one.  So here is my quick replacement.  */
# ifndef LIBPORT_HAVE_ROUND
#  include <cmath>
namespace libport
{
  inline float round (float d);
  inline double round (double d);
  inline long double round (long double d);

}
# endif /* !LIBPORT_HAVE_ROUND */

/* trunc is not C++ standard (not even POSIX) and although gnulib says it
 * provides a replacement in its manual, in fact it doesn't, nor does Boost.
 * So here is my quick replacement.  */
# ifndef LIBPORT_HAVE_TRUNC
#  include <cmath>
namespace libport
{
  inline double trunc (double d);
}
# endif /* !LIBPORT_HAVE_TRUNC */

/* Float to int converter.  */
namespace libport
{
  struct bad_numeric_cast : public std::exception {};

  /// Convert a libport::ufloat to a int. Raise
  /// libport::bad_numeric_cast if the provided argument is not
  /// directly convertible to an integer.
  int ufloat_to_int(ufloat val);
  long long ufloat_to_long_long(ufloat val);

} // namespace libport

# include <libport/ufloat.hxx>

#endif // !LIBPORT_UFLOAT_HH
<commit_msg>Missing API.<commit_after>/// \file libport/ufloat.hh
/// \brief Definition of the ufloat classes.

#ifndef LIBPORT_UFLOAT_HH
# define LIBPORT_UFLOAT_HH

# include <libport/config.h>
# include <libport/export.hh>

# include <cfloat>
# include <exception>

/*-----------------.
| Ufloat support.  |
`-----------------*/

# ifdef LIBPORT_URBI_UFLOAT_FLOAT
namespace libport
{
  typedef float ufloat;
#  define UFLT_EPSILON FLT_EPSILON

  inline long long to_long_long (ufloat u);
}
# endif

# ifdef LIBPORT_URBI_UFLOAT_DOUBLE
namespace libport
{
  typedef double ufloat;
#  define UFLT_EPSILON DBL_EPSILON

  inline long long to_long_long (ufloat u);
}
# endif

# ifdef LIBPORT_URBI_UFLOAT_LONG
#  include <libport/ulong-fixed-point.hh>
# endif

# ifdef LIBPORT_URBI_UFLOAT_LONG_LONG
#  include <libport/ull-fixed-point.hh>
# endif

# ifdef LIBPORT_URBI_UFLOAT_FLOATING
#  include <libport/uffloat.hh>
# endif

namespace libport
{
  static const ufloat PI(3.14159265358979323846264338327950288);
  static const ufloat UINFINITY(999999999999999.0);
}

/*-------------------.
| Ufloat tabulated.  |
`-------------------*/

# ifdef LIBPORT_URBI_UFLOAT_TABULATED
namespace libport
{
  /** @return the tabulated sinus of given @a angle in radian, using linear
   * interpolation.  */
  ufloat tabulatedSin(ufloat angle);

  /** @return the tabulated cosinus of given @a angle in radian, using linear
   * interpolation.  */
  ufloat tabulatedCos(ufloat angle);

  /** @return the tabulated arcsinus of given @a angle, in radian, using
   * linear interpolation.  */
  ufloat tabulatedASin(ufloat angle);

  /** @return the tabulated arccosinus of given @a angle, in radian, using
   * linear interpolation.  */
  inline ufloat tabulatedACos(ufloat angle);

  inline ufloat sin(ufloat angle);
  inline ufloat cos(ufloat angle);
  inline ufloat tan(ufloat angle);

  inline ufloat asin(ufloat angle);
  inline ufloat acos(ufloat angle);
}
# endif

# include <libport/config.h>
/* round is not C++ standard (not even POSIX) and neither gnulib nor Boost
 * provide one.  So here is my quick replacement.  */
# ifndef LIBPORT_HAVE_ROUND
#  include <cmath>
namespace libport
{
  inline float round (float d);
  inline double round (double d);
  inline long double round (long double d);

}
# endif /* !LIBPORT_HAVE_ROUND */

/* trunc is not C++ standard (not even POSIX) and although gnulib says it
 * provides a replacement in its manual, in fact it doesn't, nor does Boost.
 * So here is my quick replacement.  */
# ifndef LIBPORT_HAVE_TRUNC
#  include <cmath>
namespace libport
{
  inline double trunc (double d);
}
# endif /* !LIBPORT_HAVE_TRUNC */

/* Float to int converter.  */
namespace libport
{
  struct bad_numeric_cast : public std::exception {};

  /// Convert a libport::ufloat to a int. Raise
  /// libport::bad_numeric_cast if the provided argument is not
  /// directly convertible to an integer.
  LIBPORT_API int ufloat_to_int(ufloat val);
  LIBPORT_API long long ufloat_to_long_long(ufloat val);

} // namespace libport

# include <libport/ufloat.hxx>

#endif // !LIBPORT_UFLOAT_HH
<|endoftext|>