<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: image_util.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef IMAGE_UTIL_HPP
#define IMAGE_UTIL_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/graphics.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>

// stl
#include <string>

namespace mapnik {

class Map;
class ImageWriterException : public std::exception
{
private:
    std::string message_;
public:
    ImageWriterException(const std::string& message)
        : message_(message) {}

    ~ImageWriterException() throw() {}

    virtual const char* what() const throw()
    {
        return message_.c_str();
    }
};

MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map,
                                    std::string const& filename,
                                    std::string const& type);

template <typename T>
MAPNIK_DECL void save_to_file(T const& image,
                              std::string const& filename,
                              std::string const& type);
// guess type from file extension
template <typename T>
MAPNIK_DECL void save_to_file(T const& image,
                              std::string const& filename);

template <typename T>
MAPNIK_DECL std::string save_to_string(T const& image,
                                       std::string const& type);

template <typename T>
void save_as_png(T const& image,
                 std::string const& filename);

#if defined(HAVE_JPEG)
template <typename T>
void save_as_jpeg(std::string const& filename,
                  int quality,
                  T const& image);
#endif

inline bool is_png (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".png"));
}

inline bool is_jpeg (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".jpg")) ||
        boost::algorithm::iends_with(filename,std::string(".jpeg"));
}

inline bool is_tiff (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".tif")) ||
        boost::algorithm::iends_with(filename,std::string(".tiff"));
}

inline bool is_pdf (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".pdf"));
}

inline bool is_svg (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".svg"));
}

inline bool is_ps (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".ps"));
}

inline boost::optional<std::string> type_from_filename(std::string const& filename)

{
    typedef boost::optional<std::string> result_type;
    if (is_png(filename)) return result_type("png");
    if (is_jpeg(filename)) return result_type("jpeg");
    if (is_tiff(filename)) return result_type("tiff");
    if (is_pdf(filename)) return result_type("pdf");
    if (is_svg(filename)) return result_type("svg");
    if (is_ps(filename)) return result_type("ps");
    return result_type();
}

inline std::string guess_type( const std::string & filename )
{
    std::string::size_type idx = filename.find_last_of(".");
    if ( idx != std::string::npos ) {
        return filename.substr( idx + 1 );
    }
    return "<unknown>";
}

template <typename T>
double distance(T x0,T y0,T x1,T y1)
{
    double dx = x1-x0;
    double dy = y1-y0;
    return std::sqrt(dx * dx + dy * dy);
}

// add 1-px border around image - useful for debugging alignment issues
template <typename T>
void add_border(T & image)
{
    for (unsigned  x = 0; x < image.width();++x)
    {
        image(x,0) = 0xff0000ff; // red
        image(x,image.height()-1) = 0xff00ff00; //green
    }
    for (unsigned y = 0; y < image.height();++y)
    {
        image(0,y) = 0xff00ffff; //yellow
        image(image.width()-1,y) = 0xffff0000; // blue
    }
}

template <typename Image>
inline void scale_image (Image& target,const Image& source)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int int_part_y=source_height/target_height;
    int fract_part_y=source_height%target_height;
    int err_y=0;
    int int_part_x=source_width/target_width;
    int fract_part_x=source_width%target_width;
    int err_x=0;
    int x=0,y=0,xs=0,ys=0;
    int prev_y=-1;
    for (y=0;y<target_height;++y)
    {
        if (ys==prev_y)
        {
            target.setRow(y,target.getRow(y-1),target_width);
        }
        else
        {
            xs=0;
            for (x=0;x<target_width;++x)
            {
                target(x,y)=source(xs,ys);
                xs+=int_part_x;
                err_x+=fract_part_x;
                if (err_x>=target_width)
                {
                    err_x-=target_width;
                    ++xs;
                }
            }
            prev_y=ys;
        }
        ys+=int_part_y;
        err_y+=fract_part_y;
        if (err_y>=target_height)
        {
            err_y-=target_height;
            ++ys;
        }
    }

#ifdef MAPNIK_DEBUG
    add_border(target);
#endif
}

template <typename Image>
inline void scale_image_bilinear (Image& target,const Image& source, double x_off_f=0, double y_off_f=0)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int x=0,y=0,xs=0,ys=0;
    int tw2 = target_width/2;
    int th2 = target_height/2;
    int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2);
    int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2);
    unsigned yprt, yprt1, xprt, xprt1;

    //no scaling or subpixel offset
    if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){
        for (y=0;y<target_height;++y)
            target.setRow(y,source.getRow(y),target_width);
        return;
    }

    for (y=0;y<target_height;++y)
    {
        ys = (y*source_height+offs_y)/target_height;
        int ys1 = ys+1;
        if (ys1>=source_height)
            ys1--;
        if (ys<0)
            ys=ys1=0;
        if (source_height/2<target_height)
            yprt = (y*source_height+offs_y)%target_height;
        else
            yprt = th2;
        yprt1 = target_height-yprt;
        for (x=0;x<target_width;++x)
        {
            xs = (x*source_width+offs_x)/target_width;
            if (source_width/2<target_width)
                xprt = (x*source_width+offs_x)%target_width;
            else
                xprt = tw2;
            xprt1 = target_width-xprt;
            int xs1 = xs+1;
            if (xs1>=source_width)
                xs1--;
            if (xs<0)
                xs=xs1=0;

            unsigned a = source(xs,ys);
            unsigned b = source(xs1,ys);
            unsigned c = source(xs,ys1);
            unsigned d = source(xs1,ys1);
            unsigned out=0;
            unsigned t = 0;

            for(int i=0; i<4; i++){
                unsigned p,r,s;
                // X axis
                p = a&0xff;
                r = b&0xff;
                if (p!=r)
                    r = (r*xprt+p*xprt1+tw2)/target_width;
                p = c&0xff;
                s = d&0xff;
                if (p!=s)
                    s = (s*xprt+p*xprt1+tw2)/target_width;
                // Y axis
                if (r!=s)
                    r = (s*yprt+r*yprt1+th2)/target_height;
                // channel up
                out |= r << t;
                t += 8;
                a >>= 8;
                b >>= 8;
                c >>= 8;
                d >>= 8;
            }
            target(x,y)=out;
        }
    }
}

template <typename Image>
inline void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f=0, double y_off_f=0)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int x=0,y=0,xs=0,ys=0;
    int tw2 = target_width/2;
    int th2 = target_height/2;
    int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2);
    int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2);
    unsigned yprt, yprt1, xprt, xprt1;

    //no scaling or subpixel offset
    if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){
        for (y=0;y<target_height;++y)
            target.setRow(y,source.getRow(y),target_width);
        return;
    }

    for (y=0;y<target_height;++y)
    {
        ys = (y*source_height+offs_y)/target_height;
        int ys1 = ys+1;
        if (ys1>=source_height)
            ys1--;
        if (ys<0)
            ys=ys1=0;
        if (source_height/2<target_height)
            yprt = (y*source_height+offs_y)%target_height;
        else
            yprt = th2;
        yprt1 = target_height-yprt;
        for (x=0;x<target_width;++x)
        {
            xs = (x*source_width+offs_x)/target_width;
            if (source_width/2<target_width)
                xprt = (x*source_width+offs_x)%target_width;
            else
                xprt = tw2;
            xprt1 = target_width-xprt;
            int xs1 = xs+1;
            if (xs1>=source_width)
                xs1--;
            if (xs<0)
                xs=xs1=0;

            unsigned a = source(xs,ys);
            unsigned b = source(xs1,ys);
            unsigned c = source(xs,ys1);
            unsigned d = source(xs1,ys1);
            unsigned p,r,s;
            // X axis
            p = a&0xff;
            r = b&0xff;
            if (p!=r)
                r = (r*xprt+p*xprt1+tw2)/target_width;
            p = c&0xff;
            s = d&0xff;
            if (p!=s)
                s = (s*xprt+p*xprt1+tw2)/target_width;
            // Y axis
            if (r!=s)
                r = (s*yprt+r*yprt1+th2)/target_height;
            target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r;
        }
    }
}

inline MAPNIK_DECL void save_to_file (image_32 const& image,
                                      std::string const& file,
                                      std::string const& type)
{
    save_to_file<image_data_32>(image.data(),file,type);
}

inline MAPNIK_DECL void save_to_file(image_32 const& image,
                                     std::string const& file)
{
    save_to_file<image_data_32>(image.data(),file);
}

inline MAPNIK_DECL std::string save_to_string(image_32 const& image,
                                              std::string const& type)
{
    return save_to_string<image_data_32>(image.data(),type);
}

#ifdef _MSC_VER
template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
                                                      std::string const&,
                                                      std::string const&);
template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
                                                      std::string const&);
template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
                                                               std::string const&);

template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                    std::string const&,
                                                                    std::string const&);

template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                    std::string const&);

template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                             std::string const&);
#endif

}

#endif //IMAGE_UTIL_HPP
<commit_msg>only expose save_to_cairo_file if cairo support available<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: image_util.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef IMAGE_UTIL_HPP
#define IMAGE_UTIL_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/graphics.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>

// stl
#include <string>

namespace mapnik {

class Map;
class ImageWriterException : public std::exception
{
private:
    std::string message_;
public:
    ImageWriterException(const std::string& message)
        : message_(message) {}

    ~ImageWriterException() throw() {}

    virtual const char* what() const throw()
    {
        return message_.c_str();
    }
};

#if defined(HAVE_CAIRO)
MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map,
                                    std::string const& filename,
                                    std::string const& type);
#endif

template <typename T>
MAPNIK_DECL void save_to_file(T const& image,
                              std::string const& filename,
                              std::string const& type);
// guess type from file extension
template <typename T>
MAPNIK_DECL void save_to_file(T const& image,
                              std::string const& filename);

template <typename T>
MAPNIK_DECL std::string save_to_string(T const& image,
                                       std::string const& type);

template <typename T>
void save_as_png(T const& image,
                 std::string const& filename);

#if defined(HAVE_JPEG)
template <typename T>
void save_as_jpeg(std::string const& filename,
                  int quality,
                  T const& image);
#endif

inline bool is_png (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".png"));
}

inline bool is_jpeg (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".jpg")) ||
        boost::algorithm::iends_with(filename,std::string(".jpeg"));
}

inline bool is_tiff (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".tif")) ||
        boost::algorithm::iends_with(filename,std::string(".tiff"));
}

inline bool is_pdf (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".pdf"));
}

inline bool is_svg (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".svg"));
}

inline bool is_ps (std::string const& filename)
{
    return boost::algorithm::iends_with(filename,std::string(".ps"));
}

inline boost::optional<std::string> type_from_filename(std::string const& filename)

{
    typedef boost::optional<std::string> result_type;
    if (is_png(filename)) return result_type("png");
    if (is_jpeg(filename)) return result_type("jpeg");
    if (is_tiff(filename)) return result_type("tiff");
    if (is_pdf(filename)) return result_type("pdf");
    if (is_svg(filename)) return result_type("svg");
    if (is_ps(filename)) return result_type("ps");
    return result_type();
}

inline std::string guess_type( const std::string & filename )
{
    std::string::size_type idx = filename.find_last_of(".");
    if ( idx != std::string::npos ) {
        return filename.substr( idx + 1 );
    }
    return "<unknown>";
}

template <typename T>
double distance(T x0,T y0,T x1,T y1)
{
    double dx = x1-x0;
    double dy = y1-y0;
    return std::sqrt(dx * dx + dy * dy);
}

// add 1-px border around image - useful for debugging alignment issues
template <typename T>
void add_border(T & image)
{
    for (unsigned  x = 0; x < image.width();++x)
    {
        image(x,0) = 0xff0000ff; // red
        image(x,image.height()-1) = 0xff00ff00; //green
    }
    for (unsigned y = 0; y < image.height();++y)
    {
        image(0,y) = 0xff00ffff; //yellow
        image(image.width()-1,y) = 0xffff0000; // blue
    }
}

template <typename Image>
inline void scale_image (Image& target,const Image& source)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int int_part_y=source_height/target_height;
    int fract_part_y=source_height%target_height;
    int err_y=0;
    int int_part_x=source_width/target_width;
    int fract_part_x=source_width%target_width;
    int err_x=0;
    int x=0,y=0,xs=0,ys=0;
    int prev_y=-1;
    for (y=0;y<target_height;++y)
    {
        if (ys==prev_y)
        {
            target.setRow(y,target.getRow(y-1),target_width);
        }
        else
        {
            xs=0;
            for (x=0;x<target_width;++x)
            {
                target(x,y)=source(xs,ys);
                xs+=int_part_x;
                err_x+=fract_part_x;
                if (err_x>=target_width)
                {
                    err_x-=target_width;
                    ++xs;
                }
            }
            prev_y=ys;
        }
        ys+=int_part_y;
        err_y+=fract_part_y;
        if (err_y>=target_height)
        {
            err_y-=target_height;
            ++ys;
        }
    }

#ifdef MAPNIK_DEBUG
    add_border(target);
#endif
}

template <typename Image>
inline void scale_image_bilinear (Image& target,const Image& source, double x_off_f=0, double y_off_f=0)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int x=0,y=0,xs=0,ys=0;
    int tw2 = target_width/2;
    int th2 = target_height/2;
    int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2);
    int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2);
    unsigned yprt, yprt1, xprt, xprt1;

    //no scaling or subpixel offset
    if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){
        for (y=0;y<target_height;++y)
            target.setRow(y,source.getRow(y),target_width);
        return;
    }

    for (y=0;y<target_height;++y)
    {
        ys = (y*source_height+offs_y)/target_height;
        int ys1 = ys+1;
        if (ys1>=source_height)
            ys1--;
        if (ys<0)
            ys=ys1=0;
        if (source_height/2<target_height)
            yprt = (y*source_height+offs_y)%target_height;
        else
            yprt = th2;
        yprt1 = target_height-yprt;
        for (x=0;x<target_width;++x)
        {
            xs = (x*source_width+offs_x)/target_width;
            if (source_width/2<target_width)
                xprt = (x*source_width+offs_x)%target_width;
            else
                xprt = tw2;
            xprt1 = target_width-xprt;
            int xs1 = xs+1;
            if (xs1>=source_width)
                xs1--;
            if (xs<0)
                xs=xs1=0;

            unsigned a = source(xs,ys);
            unsigned b = source(xs1,ys);
            unsigned c = source(xs,ys1);
            unsigned d = source(xs1,ys1);
            unsigned out=0;
            unsigned t = 0;

            for(int i=0; i<4; i++){
                unsigned p,r,s;
                // X axis
                p = a&0xff;
                r = b&0xff;
                if (p!=r)
                    r = (r*xprt+p*xprt1+tw2)/target_width;
                p = c&0xff;
                s = d&0xff;
                if (p!=s)
                    s = (s*xprt+p*xprt1+tw2)/target_width;
                // Y axis
                if (r!=s)
                    r = (s*yprt+r*yprt1+th2)/target_height;
                // channel up
                out |= r << t;
                t += 8;
                a >>= 8;
                b >>= 8;
                c >>= 8;
                d >>= 8;
            }
            target(x,y)=out;
        }
    }
}

template <typename Image>
inline void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f=0, double y_off_f=0)
{

    int source_width=source.width();
    int source_height=source.height();

    int target_width=target.width();
    int target_height=target.height();

    if (source_width<1 || source_height<1 ||
        target_width<1 || target_height<1) return;
    int x=0,y=0,xs=0,ys=0;
    int tw2 = target_width/2;
    int th2 = target_height/2;
    int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2);
    int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2);
    unsigned yprt, yprt1, xprt, xprt1;

    //no scaling or subpixel offset
    if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){
        for (y=0;y<target_height;++y)
            target.setRow(y,source.getRow(y),target_width);
        return;
    }

    for (y=0;y<target_height;++y)
    {
        ys = (y*source_height+offs_y)/target_height;
        int ys1 = ys+1;
        if (ys1>=source_height)
            ys1--;
        if (ys<0)
            ys=ys1=0;
        if (source_height/2<target_height)
            yprt = (y*source_height+offs_y)%target_height;
        else
            yprt = th2;
        yprt1 = target_height-yprt;
        for (x=0;x<target_width;++x)
        {
            xs = (x*source_width+offs_x)/target_width;
            if (source_width/2<target_width)
                xprt = (x*source_width+offs_x)%target_width;
            else
                xprt = tw2;
            xprt1 = target_width-xprt;
            int xs1 = xs+1;
            if (xs1>=source_width)
                xs1--;
            if (xs<0)
                xs=xs1=0;

            unsigned a = source(xs,ys);
            unsigned b = source(xs1,ys);
            unsigned c = source(xs,ys1);
            unsigned d = source(xs1,ys1);
            unsigned p,r,s;
            // X axis
            p = a&0xff;
            r = b&0xff;
            if (p!=r)
                r = (r*xprt+p*xprt1+tw2)/target_width;
            p = c&0xff;
            s = d&0xff;
            if (p!=s)
                s = (s*xprt+p*xprt1+tw2)/target_width;
            // Y axis
            if (r!=s)
                r = (s*yprt+r*yprt1+th2)/target_height;
            target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r;
        }
    }
}

inline MAPNIK_DECL void save_to_file (image_32 const& image,
                                      std::string const& file,
                                      std::string const& type)
{
    save_to_file<image_data_32>(image.data(),file,type);
}

inline MAPNIK_DECL void save_to_file(image_32 const& image,
                                     std::string const& file)
{
    save_to_file<image_data_32>(image.data(),file);
}

inline MAPNIK_DECL std::string save_to_string(image_32 const& image,
                                              std::string const& type)
{
    return save_to_string<image_data_32>(image.data(),type);
}

#ifdef _MSC_VER
template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
                                                      std::string const&,
                                                      std::string const&);
template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
                                                      std::string const&);
template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
                                                               std::string const&);

template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                    std::string const&,
                                                                    std::string const&);

template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                    std::string const&);

template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
                                                                             std::string const&);
#endif

}

#endif //IMAGE_UTIL_HPP
<|endoftext|>


<commit_before>//----------------------------  solver.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  solver.cc  ---------------------------

#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include "testmatrix.h"
#include <base/logstream.h>
#include <lac/sparse_matrix.h>
#include <lac/vector.h>
#include <lac/vector_memory.h>
#include <lac/solver_control.h>
#include <lac/solver_cg.h>
#include <lac/solver_gmres.h>
#include <lac/solver_bicgstab.h>
#include <lac/solver_richardson.h>
#include <lac/solver_qmrs.h>
#include <lac/precondition.h>

template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
void
check_solve( SOLVER& solver, const MATRIX& A,
	     VECTOR& u, VECTOR& f, const PRECONDITION& P)
{
  u = 0.;
  f = 1.;
  try
    {
      solver.solve(A,u,f,P);
    }
  catch (std::exception& e)
    {
      deallog << e.what() << std::endl;
    }
}

template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
void
check_Tsolve(SOLVER& solver, const MATRIX& A,
	     VECTOR& u, VECTOR& f, const PRECONDITION& P)
{
  u = 0.;
  f = 1.;
  try
    {
      solver.Tsolve(A,u,f,P);
    }
  catch (std::exception& e)
    {
      deallog << e.what() << std::endl;
    }
}

int main()
{
  std::ofstream logfile("solver.output");
//  logfile.setf(std::ios::fixed);
  logfile.precision(4);
  deallog.attach(logfile);
  deallog.depth_console(0);

  GrowingVectorMemory<> mem;
  SolverControl control(100, 1.e-3);
  SolverControl verbose_control(100, 1.e-3, true);
  SolverCG<> cg(control, mem);
  SolverGMRES<> gmres(control, mem, 8);
  SolverGMRES<>::AdditionalData(8, true);
  SolverGMRES<> gmresright(control, mem, 8);
  SolverBicgstab<> bicgstab(control, mem);
  SolverRichardson<> rich(control, mem);
  SolverQMRS<> qmrs(control, mem);

  for (unsigned int size=4; size <= 30; size *= 3)
    {
      unsigned int dim = (size-1)*(size-1);

      deallog << "Size " << size << " Unknowns " << dim << std::endl;

				       // Make matrix
      FDMatrix testproblem(size, size);
      SparsityPattern structure(dim, dim, 5);
      testproblem.five_point_structure(structure);
      structure.compress();
      SparseMatrix<double>  A(structure);
      testproblem.five_point(A);

      PreconditionIdentity prec_no;
      PreconditionSOR<> prec_sor;
      prec_sor.initialize(A, 1.2);
      PreconditionSSOR<> prec_ssor;
      prec_ssor.initialize(A, 1.2);

      std::vector<unsigned int> permutation(dim);
      std::vector<unsigned int> inverse_permutation(dim);
      for (unsigned int i=0;i<dim;++i)
	permutation[i] = dim-i-1;
      for (unsigned int i=0;i<dim;++i)
	inverse_permutation[permutation[i]] = i;

      PreconditionPSOR<> prec_psor;
      prec_psor.initialize(A, permutation, inverse_permutation, 1.2);

      Vector<double>  f(dim);
      Vector<double>  u(dim);
      Vector<double> res(dim);

      f = 1.;
      u = 1.;

      A.residual(res,u,f);
      A.SOR(res);
      res.add(1.,u);
      A.SOR_step(u,f);
      res.add(-1.,u);

      deallog << "SOR-diff:" << res*res << std::endl;

      try
	{
	  deallog.push("no-fail");

	  control.set_max_steps(10);
	  check_solve(cg,A,u,f,prec_no);
	  check_solve(bicgstab,A,u,f,prec_no);
	  check_solve(gmres,A,u,f,prec_no);
	  check_solve(gmresright,A,u,f,prec_no);
	  check_solve(qmrs,A,u,f,prec_no);
	  control.set_max_steps(100);

	  deallog.pop();

	  deallog.push("no");

	  check_solve(cg,A,u,f,prec_no);
	  check_solve(bicgstab,A,u,f,prec_no);
	  check_solve(gmres,A,u,f,prec_no);
	  check_solve(gmresright,A,u,f,prec_no);
	  check_solve(qmrs,A,u,f,prec_no);

	  deallog.pop();

	  deallog.push("ssor");

	  check_Tsolve(rich,A,u,f,prec_ssor);
	  check_solve(rich,A,u,f,prec_ssor);
	  check_solve(cg,A,u,f,prec_ssor);
	  check_solve(bicgstab,A,u,f,prec_ssor);
	  check_solve(gmres,A,u,f,prec_ssor);
	  check_solve(gmresright,A,u,f,prec_ssor);
	  check_solve(qmrs,A,u,f,prec_ssor);

	  deallog.pop();

	  deallog.push("sor");

	  check_Tsolve(rich,A,u,f,prec_sor);
	  check_solve(rich,A,u,f,prec_sor);
	  check_solve(cg,A,u,f,prec_sor);
	  check_solve(bicgstab,A,u,f,prec_sor);
	  check_solve(gmres,A,u,f,prec_sor);
	  check_solve(gmresright,A,u,f,prec_sor);

	  deallog.pop();

	  deallog.push("psor");

	  check_Tsolve(rich,A,u,f,prec_psor);
	  check_solve(rich,A,u,f,prec_psor);
	  check_solve(cg,A,u,f,prec_psor);
	  check_solve(bicgstab,A,u,f,prec_psor);
	  check_solve(gmres,A,u,f,prec_psor);
	  check_solve(gmresright,A,u,f,prec_psor);

	  deallog.pop();
	}
      catch (std::exception& e)
	{
	  std::cerr << e.what() << std::endl;
	}
    };
}

<commit_msg>more sophisticated permutation<commit_after>//----------------------------  solver.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  solver.cc  ---------------------------

#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include "testmatrix.h"
#include <base/logstream.h>
#include <lac/sparse_matrix.h>
#include <lac/vector.h>
#include <lac/vector_memory.h>
#include <lac/solver_control.h>
#include <lac/solver_cg.h>
#include <lac/solver_gmres.h>
#include <lac/solver_bicgstab.h>
#include <lac/solver_richardson.h>
#include <lac/solver_qmrs.h>
#include <lac/precondition.h>

template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
void
check_solve( SOLVER& solver, const MATRIX& A,
	     VECTOR& u, VECTOR& f, const PRECONDITION& P)
{
  u = 0.;
  f = 1.;
  try
    {
      solver.solve(A,u,f,P);
    }
  catch (std::exception& e)
    {
      deallog << e.what() << std::endl;
    }
}

template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
void
check_Tsolve(SOLVER& solver, const MATRIX& A,
	     VECTOR& u, VECTOR& f, const PRECONDITION& P)
{
  u = 0.;
  f = 1.;
  try
    {
      solver.Tsolve(A,u,f,P);
    }
  catch (std::exception& e)
    {
      deallog << e.what() << std::endl;
    }
}

int main()
{
  std::ofstream logfile("solver.output");
//  logfile.setf(std::ios::fixed);
  logfile.precision(4);
  deallog.attach(logfile);
  deallog.depth_console(0);

  GrowingVectorMemory<> mem;
  SolverControl control(100, 1.e-3);
  SolverControl verbose_control(100, 1.e-3, true);
  SolverCG<> cg(control, mem);
  SolverGMRES<> gmres(control, mem, 8);
  SolverGMRES<>::AdditionalData(8, true);
  SolverGMRES<> gmresright(control, mem, 8);
  SolverBicgstab<> bicgstab(control, mem);
  SolverRichardson<> rich(control, mem);
  SolverQMRS<> qmrs(control, mem);

  for (unsigned int size=4; size <= 30; size *= 3)
    {
      unsigned int dim = (size-1)*(size-1);

      deallog << "Size " << size << " Unknowns " << dim << std::endl;

				       // Make matrix
      FDMatrix testproblem(size, size);
      SparsityPattern structure(dim, dim, 5);
      testproblem.five_point_structure(structure);
      structure.compress();
      SparseMatrix<double>  A(structure);
      testproblem.five_point(A);

      PreconditionIdentity prec_no;
      PreconditionSOR<> prec_sor;
      prec_sor.initialize(A, 1.2);
      PreconditionSSOR<> prec_ssor;
      prec_ssor.initialize(A, 1.2);

      std::vector<unsigned int> permutation(dim);
      std::vector<unsigned int> inverse_permutation(dim);

				       // Create a permutation: Blocks
				       // backwards and every second
				       // block backwards
      unsigned int k = 0;
      for (unsigned int i=0;i<size-1;++i)
	for (unsigned int j=0;j<size-1;++j)
	  {
	    if (i % 2)
	      permutation[k++] = (size-i-2) * (size-1) + j;
	    else
	      permutation[k++] = (size-i-2) * (size-1) + size-j-2;
	  }

      for (unsigned int i=0;i<dim;++i)
	inverse_permutation[permutation[i]] = i;

      PreconditionPSOR<> prec_psor;
      prec_psor.initialize(A, permutation, inverse_permutation, 1.2);

      Vector<double>  f(dim);
      Vector<double>  u(dim);
      Vector<double> res(dim);

      f = 1.;
      u = 1.;

      A.residual(res,u,f);
      A.SOR(res);
      res.add(1.,u);
      A.SOR_step(u,f);
      res.add(-1.,u);

      deallog << "SOR-diff:" << res*res << std::endl;

      try
	{
	  deallog.push("no-fail");

	  control.set_max_steps(10);
	  check_solve(cg,A,u,f,prec_no);
	  check_solve(bicgstab,A,u,f,prec_no);
	  check_solve(gmres,A,u,f,prec_no);
	  check_solve(gmresright,A,u,f,prec_no);
	  check_solve(qmrs,A,u,f,prec_no);
	  control.set_max_steps(100);

	  deallog.pop();

	  deallog.push("no");

	  check_solve(cg,A,u,f,prec_no);
	  check_solve(bicgstab,A,u,f,prec_no);
	  check_solve(gmres,A,u,f,prec_no);
	  check_solve(gmresright,A,u,f,prec_no);
	  check_solve(qmrs,A,u,f,prec_no);

	  deallog.pop();

	  deallog.push("ssor");

	  check_Tsolve(rich,A,u,f,prec_ssor);
	  check_solve(rich,A,u,f,prec_ssor);
	  check_solve(cg,A,u,f,prec_ssor);
	  check_solve(bicgstab,A,u,f,prec_ssor);
	  check_solve(gmres,A,u,f,prec_ssor);
	  check_solve(gmresright,A,u,f,prec_ssor);
	  check_solve(qmrs,A,u,f,prec_ssor);

	  deallog.pop();

	  deallog.push("sor");

	  check_Tsolve(rich,A,u,f,prec_sor);
	  check_solve(rich,A,u,f,prec_sor);
	  check_solve(cg,A,u,f,prec_sor);
	  check_solve(bicgstab,A,u,f,prec_sor);
	  check_solve(gmres,A,u,f,prec_sor);
	  check_solve(gmresright,A,u,f,prec_sor);

	  deallog.pop();

	  deallog.push("psor");

	  check_Tsolve(rich,A,u,f,prec_psor);
	  check_solve(rich,A,u,f,prec_psor);
	  check_solve(cg,A,u,f,prec_psor);
	  check_solve(bicgstab,A,u,f,prec_psor);
	  check_solve(gmres,A,u,f,prec_psor);
	  check_solve(gmresright,A,u,f,prec_psor);

	  deallog.pop();
	}
      catch (std::exception& e)
	{
	  std::cerr << e.what() << std::endl;
	}
    };
}

<|endoftext|>


<commit_before>#include <3ds.h>
#include <stdio.h>
#include <string>
#include <unistd.h>

using namespace std;

// Get length of an array
template <typename T,unsigned S>
inline unsigned arraysize(const T (&v)[S]) { return S; }

int main(void)
{
	string menu[] = {"Server1", "Server2", "Server3", "Server4", "Server5", "Server6", "Server7", "Server8", "Server9", "Server10", "Server11", "Server12", "Server13", "Server14", "Server15", "Server16", "Server17", "Server18", "Server19", "Server20"};
	unsigned int pointer = 0;

	// Initialize services
	gfxInitDefault();
	consoleInit(GFX_TOP, NULL);  //TODO: Change to Bottom

	printf("Menu\n\n");
	printf(("\x1b[31m" + menu[0] + "\x1b[0m\n").c_str());

	for (unsigned int i=1; i< arraysize(menu); i++)
		printf((menu[i] + "\n").c_str());

	while (aptMainLoop())
	{
	    printf("\x1b[30;1H%i", pointer);
		//Scan all the inputs. This should be done once for each frame
		hidScanInput();

		//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
		u32 kDown = hidKeysDown();

		if (kDown & KEY_START) break; // break in order to return to hbmenu

		//Do the keys printing only if keys have changed
		if (kDown & KEY_DUP || kDown & KEY_DDOWN){
			if (kDown & KEY_DUP){
				pointer -= 1;
				if (pointer == (unsigned) -1){
					pointer = arraysize(menu) - 1;
				}
			}
			else if (kDown & KEY_DDOWN){
				pointer += 1;
				if(pointer == arraysize(menu)){
					pointer = 0;
				}
			}
			consoleClear();
			printf("Menu\n\n");

			for (unsigned int i=0; i< arraysize(menu); ++i){
				if (i == pointer)
					printf(("\x1b[31m" + menu[i] + "\x1b[0m\n").c_str());
				else{
					printf((menu[i] + "\n").c_str());
				}
			}

		}

		// Flush and swap framebuffers
		gfxFlushBuffers();
		gfxSwapBuffers();

		//Wait for VBlank
		gspWaitForVBlank();
	}
	// Exit services
	gfxExit();
	return 0;
}
<commit_msg>add experimental channels system<commit_after>#include <3ds.h>
#include <stdio.h>
#include <string>
#include <unistd.h>

using namespace std;

// Get length of an array
template <typename T,unsigned S>
inline unsigned arraysize(const T (&v)[S]) {
    return S;
}

int main(void)
{
	string menu[] = {"Server1", "Server2", "Server3", "Server4", "Server5", "Server6", "Server7", "Server8", "Server9", "Server10", "Server11", "Server12", "Server13", "Server14", "Server15", "Server16", "Server17", "Server18", "Server19", "Server20"};
	//Will be set by Discord API for each server in a Channel type array
	string channels[] = {"Channel 1", "Channel 2", "Channel 3"};
	unsigned int pointer = 0;
	unsigned int pointerChan = 0;

	// Initialize services
	gfxInitDefault();
	//We need one PrintConsole for each screen
	PrintConsole topScreen, bottomScreen;
	//Initialize console for both screen
	consoleInit(GFX_TOP, &topScreen);
	consoleInit(GFX_BOTTOM, &bottomScreen);

    //Initialize servers menu on the bottom screen
    consoleSelect(&bottomScreen);
	printf("Menu\n\n");
	printf(("\x1b[31m" + menu[0] + "\x1b[0m\n").c_str());
	for (unsigned int i=1; i< arraysize(menu); i++)
		printf((menu[i] + "\n").c_str());

	while (aptMainLoop())
	{
	    printf("\x1b[30;1H%i", pointer);
		//Scan all the inputs. This should be done once for each frame
		hidScanInput();

		//hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
		u32 kDown = hidKeysDown();

		if (kDown & KEY_START) break; // break in order to return to hbmenu

		//Do the keys printing only if keys have changed
		if (kDown & KEY_DUP || kDown & KEY_DDOWN || kDown & KEY_A){
			if (kDown & KEY_DUP){
				pointer -= 1;
				if (pointer == (unsigned) -1)
					pointer = arraysize(menu) - 1;
			}
			else if (kDown & KEY_DDOWN){
				pointer += 1;
				if(pointer == arraysize(menu))
					pointer = 0;
			}
			else if (kDown & KEY_A){
                    consoleClear();
                    printf((menu[pointer] + "\n\n").c_str());
                    printf(("\x1b[31m" + channels[0] + "\x1b[0m\n").c_str());
                    for (unsigned int i=1; i< arraysize(channels); i++){
                        printf((channels[i] + "\n").c_str());
                    }

                while (true){
                    hidScanInput();
                    kDown = hidKeysDown();
                    if (kDown & KEY_B) break;

                    if (kDown & KEY_DUP || kDown & KEY_DDOWN){
                        if (kDown & KEY_DUP){
                            pointerChan -= 1;
                            if (pointerChan == (unsigned) -1)
                                pointerChan = arraysize(channels) - 1;
                        }
                        else if (kDown & KEY_DDOWN){
                            pointerChan += 1;
                            if(pointerChan == arraysize(channels))
                                pointerChan = 0;
                        }

                        consoleClear();
                        printf((menu[pointer] + "\n\n").c_str());
                        for (unsigned int i=0; i< arraysize(channels); ++i){
                            if (i == pointerChan)
                                printf(("\x1b[31m" + channels[i] + "\x1b[0m\n").c_str());
                            else
                                printf((channels[i] + "\n").c_str());
                        }
                    }
                }
			}

			consoleClear();
			printf("Menu\n\n");

			for (unsigned int i=0; i< arraysize(menu); ++i){
				if (i == pointer)
					printf(("\x1b[31m" + menu[i] + "\x1b[0m\n").c_str());
				else
					printf((menu[i] + "\n").c_str());
			}
		}

		// Flush and swap framebuffers
		gfxFlushBuffers();
		gfxSwapBuffers();

		//Wait for VBlank
		gspWaitForVBlank();
	}
	// Exit services
	gfxExit();
	return 0;
}
<|endoftext|>


<commit_before>#ifndef K3_RUNTIME_MESSAGEPROC_H
#define K3_RUNTIME_MESSAGEPROC_H

#include <k3/runtime/Dispatch.hpp>

namespace K3
{
  //-------------------
  // Message processor

  enum class MPStatus = { Continue, Error, Done };

  template<typename Value>
  class MessageProcessor {
    public:
    MPStatus process(Message<Value> msg) {}
  };

  // Message Processor used by generated code. Processing is done by dispatch messages using a
  // generated table of triggers. The trigger wrapper functions perform the deserialization of the
  // message payload themeselves.
  template <typename Value>
  class DispatchMessageProcessor : public MessageProcessor {
  public:
    DispatchMessageProcessor(TriggerDispatch td): table(td) {}

    MPStatus process(Message<Value> msg) {

        TriggerWrapper tw;

        // Look the trigger up in the dispatch table, error out if not present.
        try {
            tw = table.at(msg.id());
        } catch (std::out_of_range e) {
            return LoopStatus::Error;
        }

        // Call the trigger.
        tw(msg.contents());

        // Message was processed, signal the engine to continue.
        // TODO: Propagate trigger errors to engine, K3 error semantics?
        return LoopStatus::Continue;
    }
  private:
    TriggerDispatch table;
  }
}

#endif
<commit_msg>Revise MessageProcessor architecture to prior model.<commit_after>#ifndef K3_RUNTIME_MESSAGEPROC_H
#define K3_RUNTIME_MESSAGEPROC_H

#include <k3/runtime/Dispatch.hpp>

namespace K3
{
  //-------------------
  // Message processor

  enum class MPStatus = { Continue, Error, Done };

  template <typename Error, typename Result>
  class MPStatus {
      public:
          MPStatus tag;
          Error error;
          Result result;
  }

  template<typename Environment, typename Value>
  class MessageProcessor {
  public:
    MessageProcessor(Environment e): env(e), _status(MPStatus::Continue) {}
    virtual void initialize() {}
    virtual void finalize() {}
    virtual void MPStatus process(Message<Value> msg) = 0;
    MPStatus status() { return _status };

    Environment env;
    MPStatus _status;

  };

  // Message Processor used by generated code. Processing is done by dispatch messages using a
  // generated table of triggers. The trigger wrapper functions perform the deserialization of the
  // message payload themeselves.
  template <typename Value>
  class DispatchMessageProcessor : public MessageProcessor {
  public:
    DispatchMessageProcessor(TriggerDispatch td): table(td) {}

    MPStatus process(Message<Value> msg) {

        TriggerWrapper tw;

        // Look the trigger up in the dispatch table, error out if not present.
        try {
            tw = table.at(msg.id());
        } catch (std::out_of_range e) {
            return LoopStatus::Error;
        }

        // Call the trigger.
        tw(msg.contents());

        // Message was processed, signal the engine to continue.
        // TODO: Propagate trigger errors to engine, K3 error semantics?
        return LoopStatus::Continue;
    }
  private:
    TriggerDispatch table;
  }
}

#endif
<|endoftext|>


<commit_before>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice, this list
    of conditions and the following disclaimer in the documentation and/or other materials
    provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOE HERMASZEWSKI OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#include "expression.hpp"

#include <iostream>
#include <memory>
#include <string>
#include <utility>

#include <parser/parser.hpp>
#include <parser/terminal_types.hpp>

namespace JoeLang
{
namespace Parser
{

//------------------------------------------------------------------------------
// Expression
//------------------------------------------------------------------------------

Expression::Expression()
{
}

Expression::~Expression()
{
}

bool Expression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    return AssignmentExpression::Parse( parser, token );
}

//------------------------------------------------------------------------------
// Assignment Expression
//------------------------------------------------------------------------------

AssignmentExpression::AssignmentExpression( std::unique_ptr<Expression> unary_expression,
                                            std::unique_ptr<AssignmentOperator> assignment_operator,
                                            std::unique_ptr<Expression> assignment_expression )
    :m_unaryExpression( std::move( unary_expression ) )
    ,m_assignmentOperator( std::move( assignment_operator ) )
    ,m_assignmentExpression( std::move( assignment_expression ) )
{
}

AssignmentExpression::~AssignmentExpression()
{
}

void AssignmentExpression::Print(int depth) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Assignment Expression\n";

    m_unaryExpression->Print( depth + 1 );
    m_assignmentOperator->Print( depth + 1 );
    m_assignmentExpression->Print( depth + 1 );
}

bool AssignmentExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    if( Expect< ConditionalExpression >( parser, token ) )
        return true;

    std::unique_ptr<Expression> unary_expression;
    if( !Expect< UnaryExpression >( parser, unary_expression ) )
        return false;

    std::unique_ptr<AssignmentOperator> assignment_operator;
    if( !Expect< AssignmentOperator >( parser, assignment_operator ) )
        return false;

    std::unique_ptr<Expression> assignment_expression;
    if( !Expect< AssignmentExpression >( parser, assignment_expression ) )
        return false;

    token.reset( new AssignmentExpression( std::move( unary_expression ),
                                           std::move( assignment_operator ),
                                           std::move( assignment_expression ) ) );
    return true;
}

AssignmentOperator::AssignmentOperator( Lexer::TerminalType terminal_type )
    :m_terminalType( terminal_type )
{
}

AssignmentOperator::~AssignmentOperator()
{
}

void AssignmentOperator::Print(int depth) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Assignment Operator\n";
}

//TODO
bool AssignmentOperator::Parse( Parser& parser, std::unique_ptr<AssignmentOperator>& token )
{
    if( !parser.ExpectTerminal( Lexer::EQUALS ) )
        return false;

    token.reset( new AssignmentOperator( Lexer::EQUALS ) );
    return true;
}

//------------------------------------------------------------------------------
// Conditional Expression
//------------------------------------------------------------------------------

ConditionalExpression::ConditionalExpression( std::unique_ptr<Expression> condition,
                                              std::unique_ptr<Expression> true_expression,
                                              std::unique_ptr<Expression> false_expression )
    :m_condition( std::move( condition ) )
    ,m_trueExpression( std::move( true_expression ) )
    ,m_falseExpression( std::move( false_expression ) )
{
}

ConditionalExpression::~ConditionalExpression()
{
}

void ConditionalExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Conditional Expression\n";

    m_condition->Print( depth + 1 );
    m_trueExpression->Print( depth + 1 );
    m_falseExpression->Print( depth + 1 );
}

bool ConditionalExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::unique_ptr<Expression> condition;
    if( !Expect< LogicalOrExpression >( parser, condition ) )
        return false;

    if( !parser.ExpectTerminal( Lexer::QUERY ) )
    {
        token = std::move( condition );
        return true;
    }

    std::unique_ptr<Expression> true_expression;
    if( !Expect<Expression>( parser, true_expression ) )
        return false;

    if( !parser.ExpectTerminal( Lexer::COLON ) )
        return false;

    std::unique_ptr<Expression> false_expression;
    if( !Expect<ConditionalExpression>( parser, false_expression ) )
        return false;

    token.reset( new ConditionalExpression( std::move( condition ),
                                            std::move( true_expression ),
                                            std::move( false_expression ) ) );
    return true;
}

//------------------------------------------------------------------------------
// BinaryOperatorExpression
//------------------------------------------------------------------------------

BinaryOperatorExpression::BinaryOperatorExpression( Lexer::TerminalType operator_terminal,
                                                    std::unique_ptr<Expression> left_side,
                                                    std::unique_ptr<Expression> right_side )
    :m_operatorTerminal( operator_terminal )
    ,m_leftSide( std::move( left_side ) )
    ,m_rightSide( std::move( right_side ) )
{
}

BinaryOperatorExpression::~BinaryOperatorExpression()
{
}

void BinaryOperatorExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Binary Operator Expression\n";
    m_leftSide->Print( depth + 1 );
    m_rightSide->Print( depth + 1 );
}
template< typename ExpressionType, typename SubExpressionType >
bool BinaryOperatorExpression::ParseLeftAssociative( Parser& parser, std::unique_ptr<Expression>& token,
                                  const std::vector<Lexer::TerminalType>& operator_terminals )
{
    std::unique_ptr<Expression> left;
    if( !Expect<SubExpressionType>( parser, left ) )
        return false;

    std::vector< std::pair< Lexer::TerminalType,
                            std::unique_ptr<Expression> > > rest;

    while( true )
    {
        bool cont = false;
        Lexer::TerminalType operator_terminal;
        for( Lexer::TerminalType o : operator_terminals )
        {
            if( parser.ExpectTerminal( o ) )
            {
                operator_terminal = o;
                cont = true;
                break;
            }
        }

        if( !cont )
            break;

        std::unique_ptr<Expression> next;
        if( !Expect<SubExpressionType>( parser, next ) )
            return false;

        rest.push_back( std::make_pair( operator_terminal,
                                        std::move( next ) ) );
    }

    for( auto& expression : rest )
        left.reset( new ExpressionType( expression.first,
                                        std::move( left ),
                                        std::move( expression.second ) ) );

    token = std::move( left );
    return true;
}

//template< typename ExpressionType, typename SubExpressionType >
//static bool ParseRightAssociative( Parser& parser, std::unique_ptr<Expression>& token,
                                   //const std::vector<Lexer::TerminalType>& operator_terminals );

//------------------------------------------------------------------------------
// Logical Or Expression
//------------------------------------------------------------------------------

LogicalOrExpression::LogicalOrExpression( Lexer::TerminalType operator_terminal,
                                          std::unique_ptr<Expression> left_side,
                                          std::unique_ptr<Expression> right_side )
    :BinaryOperatorExpression( operator_terminal,
                               std::move( left_side ),
                               std::move( right_side ) )
{
}

LogicalOrExpression::~LogicalOrExpression()
{
}

bool LogicalOrExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::vector<Lexer::TerminalType> operators;
    operators.push_back( Lexer::LOGICAL_OR );

    return ParseLeftAssociative<LogicalOrExpression, LogicalAndExpression>( parser, token, operators );
}

//------------------------------------------------------------------------------
// LogicalAndExpression
//------------------------------------------------------------------------------

LogicalAndExpression::LogicalAndExpression( Lexer::TerminalType operator_terminal,
                                          std::unique_ptr<Expression> left_side,
                                          std::unique_ptr<Expression> right_side )
    :BinaryOperatorExpression( operator_terminal,
                               std::move( left_side ),
                               std::move( right_side ) )
{
}

LogicalAndExpression::~LogicalAndExpression()
{
}

bool LogicalAndExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::vector<Lexer::TerminalType> operators;
    operators.push_back( Lexer::LOGICAL_AND );

    //TODO
    return ParseLeftAssociative<LogicalAndExpression, PrimaryExpression>( parser, token, operators );
}

//------------------------------------------------------------------------------
// Unary Expression
//------------------------------------------------------------------------------

UnaryExpression::UnaryExpression()
{
}

UnaryExpression::~UnaryExpression()
{
}

void UnaryExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Unary Expression\n";
}

//TODO
bool UnaryExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    return Expect<PrimaryExpression>( parser, token );
   /*
    if( !parser.ExpectTerminal( Lexer::IDENTIFIER ) )
        return false;

    token.reset( new UnaryExpression() );
    return true;
    */
}

//------------------------------------------------------------------------------
// Primary Expression
//------------------------------------------------------------------------------

PrimaryExpression::PrimaryExpression( std::string identifier )
    :m_identifier( std::move( identifier ) )
{
}

PrimaryExpression::~PrimaryExpression()
{
}

void PrimaryExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << m_identifier << "\n";
}

//TODO
bool PrimaryExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::string identifier;
    if( !parser.ExpectTerminal( Lexer::IDENTIFIER, identifier ) )
        return false;

    token.reset( new PrimaryExpression( identifier ) );
    return true;
}

} // namespace Parser
} // namespace JoeLang
<commit_msg>[+] Made operator vectors static<commit_after>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice, this list
    of conditions and the following disclaimer in the documentation and/or other materials
    provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOE HERMASZEWSKI OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#include "expression.hpp"

#include <iostream>
#include <memory>
#include <string>
#include <utility>

#include <parser/parser.hpp>
#include <parser/terminal_types.hpp>

namespace JoeLang
{
namespace Parser
{

//------------------------------------------------------------------------------
// Expression
//------------------------------------------------------------------------------

Expression::Expression()
{
}

Expression::~Expression()
{
}

bool Expression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    return AssignmentExpression::Parse( parser, token );
}

//------------------------------------------------------------------------------
// Assignment Expression
//------------------------------------------------------------------------------

AssignmentExpression::AssignmentExpression( std::unique_ptr<Expression> unary_expression,
                                            std::unique_ptr<AssignmentOperator> assignment_operator,
                                            std::unique_ptr<Expression> assignment_expression )
    :m_unaryExpression( std::move( unary_expression ) )
    ,m_assignmentOperator( std::move( assignment_operator ) )
    ,m_assignmentExpression( std::move( assignment_expression ) )
{
}

AssignmentExpression::~AssignmentExpression()
{
}

void AssignmentExpression::Print(int depth) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Assignment Expression\n";

    m_unaryExpression->Print( depth + 1 );
    m_assignmentOperator->Print( depth + 1 );
    m_assignmentExpression->Print( depth + 1 );
}

bool AssignmentExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    if( Expect< ConditionalExpression >( parser, token ) )
        return true;

    std::unique_ptr<Expression> unary_expression;
    if( !Expect< UnaryExpression >( parser, unary_expression ) )
        return false;

    std::unique_ptr<AssignmentOperator> assignment_operator;
    if( !Expect< AssignmentOperator >( parser, assignment_operator ) )
        return false;

    std::unique_ptr<Expression> assignment_expression;
    if( !Expect< AssignmentExpression >( parser, assignment_expression ) )
        return false;

    token.reset( new AssignmentExpression( std::move( unary_expression ),
                                           std::move( assignment_operator ),
                                           std::move( assignment_expression ) ) );
    return true;
}

AssignmentOperator::AssignmentOperator( Lexer::TerminalType terminal_type )
    :m_terminalType( terminal_type )
{
}

AssignmentOperator::~AssignmentOperator()
{
}

void AssignmentOperator::Print(int depth) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Assignment Operator\n";
}

//TODO
bool AssignmentOperator::Parse( Parser& parser, std::unique_ptr<AssignmentOperator>& token )
{
    if( !parser.ExpectTerminal( Lexer::EQUALS ) )
        return false;

    token.reset( new AssignmentOperator( Lexer::EQUALS ) );
    return true;
}

//------------------------------------------------------------------------------
// Conditional Expression
//------------------------------------------------------------------------------

ConditionalExpression::ConditionalExpression( std::unique_ptr<Expression> condition,
                                              std::unique_ptr<Expression> true_expression,
                                              std::unique_ptr<Expression> false_expression )
    :m_condition( std::move( condition ) )
    ,m_trueExpression( std::move( true_expression ) )
    ,m_falseExpression( std::move( false_expression ) )
{
}

ConditionalExpression::~ConditionalExpression()
{
}

void ConditionalExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Conditional Expression\n";

    m_condition->Print( depth + 1 );
    m_trueExpression->Print( depth + 1 );
    m_falseExpression->Print( depth + 1 );
}

bool ConditionalExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::unique_ptr<Expression> condition;
    if( !Expect< LogicalOrExpression >( parser, condition ) )
        return false;

    if( !parser.ExpectTerminal( Lexer::QUERY ) )
    {
        token = std::move( condition );
        return true;
    }

    std::unique_ptr<Expression> true_expression;
    if( !Expect<Expression>( parser, true_expression ) )
        return false;

    if( !parser.ExpectTerminal( Lexer::COLON ) )
        return false;

    std::unique_ptr<Expression> false_expression;
    if( !Expect<ConditionalExpression>( parser, false_expression ) )
        return false;

    token.reset( new ConditionalExpression( std::move( condition ),
                                            std::move( true_expression ),
                                            std::move( false_expression ) ) );
    return true;
}

//------------------------------------------------------------------------------
// BinaryOperatorExpression
//------------------------------------------------------------------------------

BinaryOperatorExpression::BinaryOperatorExpression( Lexer::TerminalType operator_terminal,
                                                    std::unique_ptr<Expression> left_side,
                                                    std::unique_ptr<Expression> right_side )
    :m_operatorTerminal( operator_terminal )
    ,m_leftSide( std::move( left_side ) )
    ,m_rightSide( std::move( right_side ) )
{
}

BinaryOperatorExpression::~BinaryOperatorExpression()
{
}

void BinaryOperatorExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Binary Operator Expression\n";
    m_leftSide->Print( depth + 1 );
    m_rightSide->Print( depth + 1 );
}
template< typename ExpressionType, typename SubExpressionType >
bool BinaryOperatorExpression::ParseLeftAssociative( Parser& parser, std::unique_ptr<Expression>& token,
                                  const std::vector<Lexer::TerminalType>& operator_terminals )
{
    std::unique_ptr<Expression> left;
    if( !Expect<SubExpressionType>( parser, left ) )
        return false;

    std::vector< std::pair< Lexer::TerminalType,
                            std::unique_ptr<Expression> > > rest;

    while( true )
    {
        bool cont = false;
        Lexer::TerminalType operator_terminal;
        for( Lexer::TerminalType o : operator_terminals )
        {
            if( parser.ExpectTerminal( o ) )
            {
                operator_terminal = o;
                cont = true;
                break;
            }
        }

        if( !cont )
            break;

        std::unique_ptr<Expression> next;
        if( !Expect<SubExpressionType>( parser, next ) )
            return false;

        rest.push_back( std::make_pair( operator_terminal,
                                        std::move( next ) ) );
    }

    for( auto& expression : rest )
        left.reset( new ExpressionType( expression.first,
                                        std::move( left ),
                                        std::move( expression.second ) ) );

    token = std::move( left );
    return true;
}

//template< typename ExpressionType, typename SubExpressionType >
//static bool ParseRightAssociative( Parser& parser, std::unique_ptr<Expression>& token,
                                   //const std::vector<Lexer::TerminalType>& operator_terminals );

//------------------------------------------------------------------------------
// Logical Or Expression
//------------------------------------------------------------------------------

LogicalOrExpression::LogicalOrExpression( Lexer::TerminalType operator_terminal,
                                          std::unique_ptr<Expression> left_side,
                                          std::unique_ptr<Expression> right_side )
    :BinaryOperatorExpression( operator_terminal,
                               std::move( left_side ),
                               std::move( right_side ) )
{
}

LogicalOrExpression::~LogicalOrExpression()
{
}

bool LogicalOrExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    // Why doesn't clang support initializer lists yet!
    static std::vector<Lexer::TerminalType> operators;
    if( operators.size() == 0 )
        operators.push_back( Lexer::LOGICAL_OR );

    return ParseLeftAssociative<LogicalOrExpression, LogicalAndExpression>( parser, token, operators );
}

//------------------------------------------------------------------------------
// LogicalAndExpression
//------------------------------------------------------------------------------

LogicalAndExpression::LogicalAndExpression( Lexer::TerminalType operator_terminal,
                                          std::unique_ptr<Expression> left_side,
                                          std::unique_ptr<Expression> right_side )
    :BinaryOperatorExpression( operator_terminal,
                               std::move( left_side ),
                               std::move( right_side ) )
{
}

LogicalAndExpression::~LogicalAndExpression()
{
}

bool LogicalAndExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    static std::vector<Lexer::TerminalType> operators;
    if( operators.size() == 0 )
        operators.push_back( Lexer::LOGICAL_AND );

    //TODO
    return ParseLeftAssociative<LogicalAndExpression, PrimaryExpression>( parser, token, operators );
}

//------------------------------------------------------------------------------
// Unary Expression
//------------------------------------------------------------------------------

UnaryExpression::UnaryExpression()
{
}

UnaryExpression::~UnaryExpression()
{
}

void UnaryExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << "Unary Expression\n";
}

//TODO
bool UnaryExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    return Expect<PrimaryExpression>( parser, token );
   /*
    if( !parser.ExpectTerminal( Lexer::IDENTIFIER ) )
        return false;

    token.reset( new UnaryExpression() );
    return true;
    */
}

//------------------------------------------------------------------------------
// Primary Expression
//------------------------------------------------------------------------------

PrimaryExpression::PrimaryExpression( std::string identifier )
    :m_identifier( std::move( identifier ) )
{
}

PrimaryExpression::~PrimaryExpression()
{
}

void PrimaryExpression::Print( int depth ) const
{
    for( int i = 0; i < depth * 4; ++i )
        std::cout << " ";
    std::cout << m_identifier << "\n";
}

//TODO
bool PrimaryExpression::Parse( Parser& parser, std::unique_ptr<Expression>& token )
{
    std::string identifier;
    if( !parser.ExpectTerminal( Lexer::IDENTIFIER, identifier ) )
        return false;

    token.reset( new PrimaryExpression( identifier ) );
    return true;
}

} // namespace Parser
} // namespace JoeLang
<|endoftext|>


<commit_before>/* -*- mode:C++; indent-tabs-mode:nil; -*- */
/* MIT License -- MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2019 Philipp Gypser and contributors, BTU Cottbus-Senftenberg
 */
#include "runtime/futex.hh"
#include "runtime/mlog.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/Mutex.hh"

#include <errno.h>
#include <atomic>

struct FutexQueueElem
{
    mythos::CapPtr ec;
    uint32_t* uaddr;
    FutexQueueElem* next;
};

FutexQueueElem* queueHead = nullptr;
FutexQueueElem** queueTail = &queueHead;
mythos::Mutex readLock;

static int futex_wait(
    uint32_t *uaddr, unsigned int flags, uint32_t val,
    uint32_t *abs_time, uint32_t bitset)
{
    MLOG_DETAIL(mlog::app, "futex_wait", DVARhex(uaddr), DVAR(*uaddr), DVAR(val));
    FutexQueueElem qe;
    qe.ec = mythos::localEC;
    qe.uaddr = uaddr;
    qe.next = nullptr;

    volatile uint32_t* addr = uaddr;
    { // enqueue self
        mythos::Mutex::Lock guard(readLock);
        *queueTail = &qe;
        queueTail = &qe.next;
    }

    if (val == *addr) {
        MLOG_DETAIL(mlog::app, "going to wait", DVAR(mythos::localEC));
        auto sysret = mythos::syscall_wait();
    }else{
        MLOG_DETAIL(mlog::app, "val != *addr");
    }

    {
	//todo: only lock futex if qe.next != 1ul
        mythos::Mutex::Lock guard(readLock);
	    if (reinterpret_cast<uint64_t>(qe.next) != 1ul) {
		MLOG_DETAIL(mlog::app, "next != 1 -> remove this element from queue");
		auto curr = &queueHead;
		while (*curr) {
		    if ((*curr)->next == &qe){
			if (queueTail == &qe.next) {
				MLOG_DETAIL(mlog::app, "last elem in queue");
				queueTail = curr;
		    	}
		    	(*curr)->next = qe.next;
			break;
		    }
		    curr = &(*curr)->next;
		}

	    }
    }

    MLOG_DETAIL(mlog::app, "Return from futex_wait");
    return 0;
}

static int futex_wake(
    uint32_t *uaddr, unsigned int flags, int nr_wake, uint32_t bitset)
{
    MLOG_DETAIL(mlog::app, "Futex_wake", DVARhex(uaddr), DVAR(*uaddr));
    mythos::Mutex::Lock guard(readLock);

    auto curr = &queueHead;
    for (int i = 0; i < nr_wake; i++) {
        while ((*curr) && (*curr)->uaddr != uaddr) {
            MLOG_DETAIL(mlog::app, "Skip entry", DVARhex((*curr)->uaddr), DVAR((*curr)->ec), DVAR((*curr)->next) );
            curr = &(*curr)->next;
        }

        if (*curr) {
            MLOG_DETAIL(mlog::app, "Found entry matching" );
	    if (queueTail == &(*curr)->next) {
		MLOG_DETAIL(mlog::app, "last elem in queue");
		queueTail = curr;
	    }
            auto entry = *curr;
            *curr = entry->next;
	    auto ec = entry->ec;
            entry->next = reinterpret_cast<FutexQueueElem*>(1ul);
            MLOG_DETAIL(mlog::app, "Wake EC", DVAR(ec) );
            mythos::syscall_signal(ec);
        } else {
            MLOG_DETAIL(mlog::app, "Reached end of queue" );
            return 0;
        }
    }
    return 0;
}

long do_futex(
    uint32_t *uaddr, int op, uint32_t val, uint32_t *timeout,
    uint32_t *uaddr2, uint32_t val2, uint32_t val3)
{
    int cmd = op & FUTEX_CMD_MASK;
    unsigned int flags = 0;

    //if (!(op & FUTEX_PRIVATE_FLAG))
        //flags |= FLAGS_SHARED;

    if (op & FUTEX_CLOCK_REALTIME) {
        flags |= FLAGS_CLOCKRT;
        if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
            cmd != FUTEX_WAIT_REQUEUE_PI)
            return -ENOSYS;
    }

    switch (cmd) {
    case FUTEX_WAIT:
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT");
        val3 = FUTEX_BITSET_MATCH_ANY;
        /* fall through */
    case FUTEX_WAIT_BITSET:
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT_BITSET");
        return futex_wait(uaddr, flags, val, timeout, val3);
    case FUTEX_WAKE:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE");
        val3 = FUTEX_BITSET_MATCH_ANY;
        /* fall through */
    case FUTEX_WAKE_BITSET:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE_BITSET");
        return futex_wake(uaddr, flags, val, val3);
    case FUTEX_REQUEUE:
        MLOG_DETAIL(mlog::app, "FUTEX_REQUEUE");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
    case FUTEX_CMP_REQUEUE:
        MLOG_DETAIL(mlog::app, "FUTEX_CMP_REQUEUE");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
    case FUTEX_WAKE_OP:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE_OP");
        return -ENOSYS;//futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
    case FUTEX_LOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_LOCK_PI");
        return -ENOSYS;//futex_lock_pi(uaddr, flags, timeout, 0);
    case FUTEX_UNLOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_UNLOCK_PI");
        return -ENOSYS;//futex_unlock_pi(uaddr, flags);
    case FUTEX_TRYLOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_TRYLOCK_PI");
        return -ENOSYS;//futex_lock_pi(uaddr, flags, NULL, 1);
    case FUTEX_WAIT_REQUEUE_PI:
        val3 = FUTEX_BITSET_MATCH_ANY;
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT_REQUEUE_PI");
        return -ENOSYS;//futex_wait_requeue_pi(uaddr, flags, val, timeout, val3, uaddr2);
    case FUTEX_CMP_REQUEUE_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_CMP_REQUEUE_PI");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
    }
    return -ENOSYS;
}
<commit_msg>fixed futex again.....<commit_after>/* -*- mode:C++; indent-tabs-mode:nil; -*- */
/* MIT License -- MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2019 Philipp Gypser and contributors, BTU Cottbus-Senftenberg
 */
#include "runtime/futex.hh"
#include "runtime/mlog.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/Mutex.hh"

#include <errno.h>
#include <atomic>

struct FutexQueueElem
{
    mythos::CapPtr ec;
    uint32_t* uaddr;
    FutexQueueElem* next;
};

FutexQueueElem* queueHead = nullptr;
FutexQueueElem** queueTail = &queueHead;
mythos::Mutex readLock;

static int futex_wait(
    uint32_t *uaddr, unsigned int flags, uint32_t val,
    uint32_t *abs_time, uint32_t bitset)
{
    MLOG_DETAIL(mlog::app, "futex_wait", DVARhex(uaddr), DVAR(*uaddr), DVAR(val));
    FutexQueueElem qe;
    qe.ec = mythos::localEC;
    qe.uaddr = uaddr;
    qe.next = nullptr;

    volatile uint32_t* addr = uaddr;
    { // enqueue self
        mythos::Mutex::Lock guard(readLock);
        *queueTail = &qe;
        queueTail = &qe.next;
    }

    if (val == *addr) {
        MLOG_DETAIL(mlog::app, "going to wait", DVAR(mythos::localEC));
        auto sysret = mythos::syscall_wait();
    }else{
        MLOG_DETAIL(mlog::app, "val != *addr");
    }

    {
	//todo: only lock futex if qe.next != 1ul
        mythos::Mutex::Lock guard(readLock);
	    if (reinterpret_cast<uint64_t>(qe.next) != 1ul) {
		MLOG_DETAIL(mlog::app, "next != 1 -> remove this element from queue");
		auto curr = &queueHead;
		while (*curr) {
		    if ((*curr)->next == &qe){
			if (queueTail == &qe.next) {
				MLOG_DETAIL(mlog::app, "last elem in queue");
				queueTail = &(*curr)->next;
		    	}
		    	(*curr)->next = qe.next;
			break;
		    }
		    curr = &(*curr)->next;
		}

	    }
    }

    MLOG_DETAIL(mlog::app, "Return from futex_wait");
    return 0;
}

static int futex_wake(
    uint32_t *uaddr, unsigned int flags, int nr_wake, uint32_t bitset)
{
    MLOG_DETAIL(mlog::app, "Futex_wake", DVARhex(uaddr), DVAR(*uaddr));
    mythos::Mutex::Lock guard(readLock);

    auto curr = &queueHead;
    for (int i = 0; i < nr_wake; i++) {
        while ((*curr) && (*curr)->uaddr != uaddr) {
            MLOG_DETAIL(mlog::app, "Skip entry", DVARhex((*curr)->uaddr), DVAR((*curr)->ec), DVAR((*curr)->next) );
            curr = &(*curr)->next;
        }

        if (*curr) {
            MLOG_DETAIL(mlog::app, "Found entry matching" );
	    if (queueTail == &(*curr)->next) {
		MLOG_DETAIL(mlog::app, "last elem in queue");
		queueTail = curr;
	    }
            auto entry = *curr;
            *curr = entry->next;
	    auto ec = entry->ec;
            entry->next = reinterpret_cast<FutexQueueElem*>(1ul);
            MLOG_DETAIL(mlog::app, "Wake EC", DVAR(ec) );
            mythos::syscall_signal(ec);
        } else {
            MLOG_DETAIL(mlog::app, "Reached end of queue" );
            return 0;
        }
    }
    return 0;
}

long do_futex(
    uint32_t *uaddr, int op, uint32_t val, uint32_t *timeout,
    uint32_t *uaddr2, uint32_t val2, uint32_t val3)
{
    int cmd = op & FUTEX_CMD_MASK;
    unsigned int flags = 0;

    //if (!(op & FUTEX_PRIVATE_FLAG))
        //flags |= FLAGS_SHARED;

    if (op & FUTEX_CLOCK_REALTIME) {
        flags |= FLAGS_CLOCKRT;
        if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
            cmd != FUTEX_WAIT_REQUEUE_PI)
            return -ENOSYS;
    }

    switch (cmd) {
    case FUTEX_WAIT:
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT");
        val3 = FUTEX_BITSET_MATCH_ANY;
        /* fall through */
    case FUTEX_WAIT_BITSET:
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT_BITSET");
        return futex_wait(uaddr, flags, val, timeout, val3);
    case FUTEX_WAKE:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE");
        val3 = FUTEX_BITSET_MATCH_ANY;
        /* fall through */
    case FUTEX_WAKE_BITSET:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE_BITSET");
        return futex_wake(uaddr, flags, val, val3);
    case FUTEX_REQUEUE:
        MLOG_DETAIL(mlog::app, "FUTEX_REQUEUE");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
    case FUTEX_CMP_REQUEUE:
        MLOG_DETAIL(mlog::app, "FUTEX_CMP_REQUEUE");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
    case FUTEX_WAKE_OP:
        MLOG_DETAIL(mlog::app, "FUTEX_WAKE_OP");
        return -ENOSYS;//futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
    case FUTEX_LOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_LOCK_PI");
        return -ENOSYS;//futex_lock_pi(uaddr, flags, timeout, 0);
    case FUTEX_UNLOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_UNLOCK_PI");
        return -ENOSYS;//futex_unlock_pi(uaddr, flags);
    case FUTEX_TRYLOCK_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_TRYLOCK_PI");
        return -ENOSYS;//futex_lock_pi(uaddr, flags, NULL, 1);
    case FUTEX_WAIT_REQUEUE_PI:
        val3 = FUTEX_BITSET_MATCH_ANY;
        MLOG_DETAIL(mlog::app, "FUTEX_WAIT_REQUEUE_PI");
        return -ENOSYS;//futex_wait_requeue_pi(uaddr, flags, val, timeout, val3, uaddr2);
    case FUTEX_CMP_REQUEUE_PI:
        MLOG_DETAIL(mlog::app, "FUTEX_CMP_REQUEUE_PI");
        return -ENOSYS;//futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
    }
    return -ENOSYS;
}
<|endoftext|>