<commit_before>// XDRStreamUnMarshaller.cc

// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: Patrick West <pwest@ucar.edu>
//
// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPYRIGHT URI/MIT 1994-1999
// Please read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
//      pwest       Patrick West <pwest@ucar.edu>
#include "config.h"
#include "XDRStreamUnMarshaller.h"

#include <cstring> // for memcpy
#include <string>
#include <sstream>

//#define DODS_DEBUG2 1
//#define DODS_DEBUG 1

#include "Str.h"
// #include "Vector.h"
#include "Array.h"
#include "util.h"
#include "InternalErr.h"
#include "debug.h"

namespace libdap {

char *XDRStreamUnMarshaller::d_buf = 0;

XDRStreamUnMarshaller::XDRStreamUnMarshaller(istream &in) : /*&d_source( 0 ),*/
        d_in(in)
{
    if (!d_buf)
        d_buf = (char *) malloc(XDR_DAP_BUFF_SIZE);
    if (!d_buf)
        throw Error(internal_error, "Failed to allocate memory for data serialization.");

    //&d_source = new XDR;
    xdrmem_create(&d_source, d_buf, XDR_DAP_BUFF_SIZE, XDR_DECODE);
}

XDRStreamUnMarshaller::XDRStreamUnMarshaller() :
        UnMarshaller(), /*&d_source( 0 ),*/d_in(cin)
{
    throw InternalErr(__FILE__, __LINE__, "Default constructor not implemented.");
}

XDRStreamUnMarshaller::XDRStreamUnMarshaller(const XDRStreamUnMarshaller &um) :
        UnMarshaller(um), /*&d_source( 0 ),*/d_in(cin)
{
    throw InternalErr(__FILE__, __LINE__, "Copy constructor not implemented.");
}

XDRStreamUnMarshaller &
XDRStreamUnMarshaller::operator=(const XDRStreamUnMarshaller &)
{
    throw InternalErr(__FILE__, __LINE__, "Copy operator not implemented.");

    return *this;
}

XDRStreamUnMarshaller::~XDRStreamUnMarshaller()
{
    xdr_destroy( &d_source );
    //&d_source = 0;
}

void XDRStreamUnMarshaller::get_byte(dods_byte &val)
{
    if (xdr_setpos( &d_source, 0 ) < 0)
        throw Error("Failed to reposition input stream");
    if (!(d_in.read(d_buf, 4))) {
        if (d_in.eof())
            throw Error("Premature EOF in input stream");
        else {
            ostringstream ss("Error reading from input stream: ");
            ss << d_in.rdstate();
            throw Error(ss.str());
        }
    }

    DBG2( std::cerr << "_in.gcount(): " << d_in.gcount() << std::endl ); DBG2( std::cerr << "_in.tellg(): " << d_in.tellg() << std::endl ); DBG2( std::cerr << "_buf[0]: " << hex << d_buf[0] << "; _buf[1]: " << d_buf[1]
            << "; _buf[2]: " << d_buf[2] << "; _buf[3]: " << d_buf[3]
            << dec << std::endl );

    if (!xdr_char(&d_source, (char *) &val))
        throw Error("Network I/O Error. Could not read byte data.");

    DBG2(std::cerr << "get_byte: " << val << std::endl );
}

void XDRStreamUnMarshaller::get_int16(dods_int16 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_INT16(&d_source, &val))
        throw Error("Network I/O Error. Could not read int 16 data.");
}

void XDRStreamUnMarshaller::get_int32(dods_int32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_INT32(&d_source, &val))
        throw Error("Network I/O Error. Could not read int 32 data.");
}

void XDRStreamUnMarshaller::get_float32(dods_float32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!xdr_float(&d_source, &val))
        throw Error("Network I/O Error. Could not read float 32 data.");
}

void XDRStreamUnMarshaller::get_float64(dods_float64 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 8);

    if (!xdr_double(&d_source, &val))
        throw Error("Network I/O Error. Could not read float 64 data.");
}

void XDRStreamUnMarshaller::get_uint16(dods_uint16 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_UINT16(&d_source, &val))
        throw Error("Network I/O Error. Could not read uint 16 data.");
}

void XDRStreamUnMarshaller::get_uint32(dods_uint32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_UINT32(&d_source, &val))
        throw Error("Network I/O Error. Could not read uint 32 data.");
}

void XDRStreamUnMarshaller::get_str(string &val)
{
    int i;
    get_int(i);
    DBG(std::cerr << "i: " << i << std::endl);

    // Must round up string size to next 4
    i = ((i + 3) / 4) * 4;
    DBG(std::cerr << "i: " << i << std::endl);

    char *in_tmp = 0;
    //char *buf = 0;
    //XDR *source = 0;
    // Must address the case where the string is larger than the buffer
    if (i + 4 > XDR_DAP_BUFF_SIZE) {
#if 0
        char *buf = (char *) malloc(i + 4);
        if (!buf)
            throw InternalErr(__FILE__, __LINE__, "Error allocating memory");
#endif
        vector<char> buf(i+4);

        XDR source;// = new XDR;
        xdrmem_create(&source, &buf[0], i + 4, XDR_DECODE);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, i);

        xdr_setpos( &source, 0);
        if (!xdr_string( &source, &in_tmp, max_str_len)) {
            xdr_destroy( &source );
            throw Error("Network I/O Error. Could not read string data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, i);

        xdr_setpos( &d_source, 0);
        if (!xdr_string(&d_source, &in_tmp, max_str_len))
            throw Error("Network I/O Error. Could not read string data.");
    }

    val = in_tmp;

    free(in_tmp);
}

void XDRStreamUnMarshaller::get_url(string &val)
{
    get_str(val);
}

void XDRStreamUnMarshaller::get_opaque(char *val, unsigned int len)
{
    xdr_setpos( &d_source, 0);

    // Round len up to the next multiple of 4. There is also the RNDUP()
    // macro in xdr.h, at least on OS/X.
    len += len & 3;
    if (static_cast<int>(len) > XDR_DAP_BUFF_SIZE)
        throw Error("Network I/O Error. Length of opaque data larger than allowed");

    d_in.read(d_buf, len);

    xdr_opaque(&d_source, val, len);
}

void XDRStreamUnMarshaller::get_int(int &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!xdr_int(&d_source, &val))
        throw Error("Network I/O Error(1).");

    DBG(std::cerr << "get_int: " << val << std::endl);
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, Vector &)
{
    int i;
    get_int(i); // This leaves the XDR encoded value in d_buf; used later
    DBG(std::cerr << "i: " << i << std::endl);

    // Must round up string size to next 4
    i += i & 3;
    DBG(std::cerr << "i: " << i << std::endl);

    //char *buf = 0;
    //XDR *source = 0;
    // Must address the case where the string is larger than the buffer
    if (i + 4 > XDR_DAP_BUFF_SIZE) {
    	vector<char> buf(i+4);
        XDR source;
        xdrmem_create(&source, &buf[0], i + 4, XDR_DECODE);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, i);
        DBG2(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&source, 0);
        if (!xdr_bytes(&d_source, val, &num, DODS_MAX_ARRAY)) {
            xdr_destroy(&source);
            throw Error("Network I/O Error. Could not read byte array data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, i);
        DBG2(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&d_source, 0);
        if (!xdr_bytes(&d_source, val, &num, DODS_MAX_ARRAY))
            throw Error("Network I/O Error. Could not read byte array data.");
    }
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, int width, Vector &vec)
{
    get_vector(val, num, width, vec.var()->type());
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, int width, Type type)
{
    int i;
    get_int(i); // This leaves the XDR encoded value in d_buf; used later
    DBG(std::cerr << "i: " << i << std::endl);

    width += width & 3;
    DBG(std::cerr << "width: " << width << std::endl);

    int size = i * width; // + 4; // '+ 4' to hold the int already read

    // Must address the case where the string is larger than the buffer
    if (size > XDR_DAP_BUFF_SIZE) {
    	vector<char> buf(size+4);
        XDR source;
        xdrmem_create(&source, &buf[0], size + 4, XDR_DECODE);
        DBG(cerr << "size: " << size << endl);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, size); // +4 for the int already read
        DBG(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&source, 0);
        if (!xdr_array(&source, val, &num, DODS_MAX_ARRAY, width, XDRUtils::xdr_coder(type))) {
            xdr_destroy( &source );
            throw Error("Network I/O Error. Could not read array data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, size);
        DBG(cerr << "bytes read (2): " << d_in.gcount() << endl);

        xdr_setpos( &d_source, 0);
        if (!xdr_array(&d_source, val, &num, DODS_MAX_ARRAY, width, XDRUtils::xdr_coder(type)))
            throw Error("Network I/O Error. Could not read array data.");
    }
}

void XDRStreamUnMarshaller::dump(ostream &strm) const
{
    strm << DapIndent::LMarg << "XDRStreamUnMarshaller::dump - (" << (void *) this << ")" << endl;
}

} // namespace libdap

<commit_msg>Fixed ugly DBG2() macro calls<commit_after>// XDRStreamUnMarshaller.cc

// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: Patrick West <pwest@ucar.edu>
//
// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPYRIGHT URI/MIT 1994-1999
// Please read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
//      pwest       Patrick West <pwest@ucar.edu>
#include "config.h"
#include "XDRStreamUnMarshaller.h"

#include <cstring> // for memcpy
#include <string>
#include <sstream>

//#define DODS_DEBUG2 1
//#define DODS_DEBUG 1

#include "Str.h"
// #include "Vector.h"
#include "Array.h"
#include "util.h"
#include "InternalErr.h"
#include "debug.h"

namespace libdap {

char *XDRStreamUnMarshaller::d_buf = 0;

XDRStreamUnMarshaller::XDRStreamUnMarshaller(istream &in) : /*&d_source( 0 ),*/
        d_in(in)
{
    if (!d_buf)
        d_buf = (char *) malloc(XDR_DAP_BUFF_SIZE);
    if (!d_buf)
        throw Error(internal_error, "Failed to allocate memory for data serialization.");

    //&d_source = new XDR;
    xdrmem_create(&d_source, d_buf, XDR_DAP_BUFF_SIZE, XDR_DECODE);
}

XDRStreamUnMarshaller::XDRStreamUnMarshaller() :
        UnMarshaller(), /*&d_source( 0 ),*/d_in(cin)
{
    throw InternalErr(__FILE__, __LINE__, "Default constructor not implemented.");
}

XDRStreamUnMarshaller::XDRStreamUnMarshaller(const XDRStreamUnMarshaller &um) :
        UnMarshaller(um), /*&d_source( 0 ),*/d_in(cin)
{
    throw InternalErr(__FILE__, __LINE__, "Copy constructor not implemented.");
}

XDRStreamUnMarshaller &
XDRStreamUnMarshaller::operator=(const XDRStreamUnMarshaller &)
{
    throw InternalErr(__FILE__, __LINE__, "Copy operator not implemented.");

    return *this;
}

XDRStreamUnMarshaller::~XDRStreamUnMarshaller()
{
    xdr_destroy( &d_source );
    //&d_source = 0;
}

void XDRStreamUnMarshaller::get_byte(dods_byte &val)
{
    if (xdr_setpos( &d_source, 0 ) < 0)
        throw Error("Failed to reposition input stream");
    if (!(d_in.read(d_buf, 4))) {
        if (d_in.eof())
            throw Error("Premature EOF in input stream");
        else {
            ostringstream ss("Error reading from input stream: ");
            ss << d_in.rdstate();
            throw Error(ss.str());
        }
    }

    DBG2( std::cerr << "_in.gcount(): " << d_in.gcount() << std::endl );
    DBG2( std::cerr << "_in.tellg(): " << d_in.tellg() << std::endl );
    DBG2( std::cerr << "_buf[0]: " << hex << d_buf[0] << "; _buf[1]: " << d_buf[1]
            << "; _buf[2]: " << d_buf[2] << "; _buf[3]: " << d_buf[3]
            << dec << std::endl );

    if (!xdr_char(&d_source, (char *) &val))
        throw Error("Network I/O Error. Could not read byte data.");

    DBG2(std::cerr << "get_byte: " << val << std::endl );
}

void XDRStreamUnMarshaller::get_int16(dods_int16 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_INT16(&d_source, &val))
        throw Error("Network I/O Error. Could not read int 16 data.");
}

void XDRStreamUnMarshaller::get_int32(dods_int32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_INT32(&d_source, &val))
        throw Error("Network I/O Error. Could not read int 32 data.");
}

void XDRStreamUnMarshaller::get_float32(dods_float32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!xdr_float(&d_source, &val))
        throw Error("Network I/O Error. Could not read float 32 data.");
}

void XDRStreamUnMarshaller::get_float64(dods_float64 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 8);

    if (!xdr_double(&d_source, &val))
        throw Error("Network I/O Error. Could not read float 64 data.");
}

void XDRStreamUnMarshaller::get_uint16(dods_uint16 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_UINT16(&d_source, &val))
        throw Error("Network I/O Error. Could not read uint 16 data.");
}

void XDRStreamUnMarshaller::get_uint32(dods_uint32 &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!XDR_UINT32(&d_source, &val))
        throw Error("Network I/O Error. Could not read uint 32 data.");
}

void XDRStreamUnMarshaller::get_str(string &val)
{
    int i;
    get_int(i);
    DBG(std::cerr << "i: " << i << std::endl);

    // Must round up string size to next 4
    i = ((i + 3) / 4) * 4;
    DBG(std::cerr << "i: " << i << std::endl);

    char *in_tmp = 0;
    //char *buf = 0;
    //XDR *source = 0;
    // Must address the case where the string is larger than the buffer
    if (i + 4 > XDR_DAP_BUFF_SIZE) {
#if 0
        char *buf = (char *) malloc(i + 4);
        if (!buf)
            throw InternalErr(__FILE__, __LINE__, "Error allocating memory");
#endif
        vector<char> buf(i+4);

        XDR source;// = new XDR;
        xdrmem_create(&source, &buf[0], i + 4, XDR_DECODE);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, i);

        xdr_setpos( &source, 0);
        if (!xdr_string( &source, &in_tmp, max_str_len)) {
            xdr_destroy( &source );
            throw Error("Network I/O Error. Could not read string data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, i);

        xdr_setpos( &d_source, 0);
        if (!xdr_string(&d_source, &in_tmp, max_str_len))
            throw Error("Network I/O Error. Could not read string data.");
    }

    val = in_tmp;

    free(in_tmp);
}

void XDRStreamUnMarshaller::get_url(string &val)
{
    get_str(val);
}

void XDRStreamUnMarshaller::get_opaque(char *val, unsigned int len)
{
    xdr_setpos( &d_source, 0);

    // Round len up to the next multiple of 4. There is also the RNDUP()
    // macro in xdr.h, at least on OS/X.
    len += len & 3;
    if (static_cast<int>(len) > XDR_DAP_BUFF_SIZE)
        throw Error("Network I/O Error. Length of opaque data larger than allowed");

    d_in.read(d_buf, len);

    xdr_opaque(&d_source, val, len);
}

void XDRStreamUnMarshaller::get_int(int &val)
{
    xdr_setpos( &d_source, 0);
    d_in.read(d_buf, 4);

    if (!xdr_int(&d_source, &val))
        throw Error("Network I/O Error(1).");

    DBG(std::cerr << "get_int: " << val << std::endl);
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, Vector &)
{
    int i;
    get_int(i); // This leaves the XDR encoded value in d_buf; used later
    DBG(std::cerr << "i: " << i << std::endl);

    // Must round up string size to next 4
    i += i & 3;
    DBG(std::cerr << "i: " << i << std::endl);

    //char *buf = 0;
    //XDR *source = 0;
    // Must address the case where the string is larger than the buffer
    if (i + 4 > XDR_DAP_BUFF_SIZE) {
    	vector<char> buf(i+4);
        XDR source;
        xdrmem_create(&source, &buf[0], i + 4, XDR_DECODE);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, i);
        DBG2(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&source, 0);
        if (!xdr_bytes(&d_source, val, &num, DODS_MAX_ARRAY)) {
            xdr_destroy(&source);
            throw Error("Network I/O Error. Could not read byte array data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, i);
        DBG2(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&d_source, 0);
        if (!xdr_bytes(&d_source, val, &num, DODS_MAX_ARRAY))
            throw Error("Network I/O Error. Could not read byte array data.");
    }
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, int width, Vector &vec)
{
    get_vector(val, num, width, vec.var()->type());
}

void XDRStreamUnMarshaller::get_vector(char **val, unsigned int &num, int width, Type type)
{
    int i;
    get_int(i); // This leaves the XDR encoded value in d_buf; used later
    DBG(std::cerr << "i: " << i << std::endl);

    width += width & 3;
    DBG(std::cerr << "width: " << width << std::endl);

    int size = i * width; // + 4; // '+ 4' to hold the int already read

    // Must address the case where the string is larger than the buffer
    if (size > XDR_DAP_BUFF_SIZE) {
    	vector<char> buf(size+4);
        XDR source;
        xdrmem_create(&source, &buf[0], size + 4, XDR_DECODE);
        DBG(cerr << "size: " << size << endl);
        memcpy(&buf[0], d_buf, 4);

        d_in.read(&buf[0] + 4, size); // +4 for the int already read
        DBG(cerr << "bytes read: " << d_in.gcount() << endl);

        xdr_setpos(&source, 0);
        if (!xdr_array(&source, val, &num, DODS_MAX_ARRAY, width, XDRUtils::xdr_coder(type))) {
            xdr_destroy( &source );
            throw Error("Network I/O Error. Could not read array data.");
        }

        xdr_destroy( &source );
    }
    else {
        d_in.read(d_buf + 4, size);
        DBG(cerr << "bytes read (2): " << d_in.gcount() << endl);

        xdr_setpos( &d_source, 0);
        if (!xdr_array(&d_source, val, &num, DODS_MAX_ARRAY, width, XDRUtils::xdr_coder(type)))
            throw Error("Network I/O Error. Could not read array data.");
    }
}

void XDRStreamUnMarshaller::dump(ostream &strm) const
{
    strm << DapIndent::LMarg << "XDRStreamUnMarshaller::dump - (" << (void *) this << ")" << endl;
}

} // namespace libdap

<|endoftext|>


<commit_before>/* Copyright © 2001-2016, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

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

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "ed/data.h"
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE test_ed
#include <boost/test/unit_test.hpp>
#include <boost/property_tree/exceptions.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "conf.h"
#include "ed/build_helper.h"
#include "ed/connectors/osm_tags_reader.h"
#include "ed/default_poi_types.h"
#include "tests/utils_test.h"

struct logger_initialized {
    logger_initialized() { navitia::init_logger(); }
};
BOOST_GLOBAL_FIXTURE(logger_initialized);

/*
 * default poi-types and minimal json should be ok
 */
BOOST_AUTO_TEST_CASE(def_json_poi_types_ok) {
    auto default_json = ed::connectors::DEFAULT_JSON_POI_TYPES;
    BOOST_CHECK_NO_THROW(const ed::connectors::PoiTypeParams params(default_json));
    auto minimal_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_NO_THROW(const ed::connectors::PoiTypeParams params(minimal_json));
}

/*
 * poi-type parking and bss-rental are mandatory (used by kraken)
 */
BOOST_AUTO_TEST_CASE(no_parking_json_poi_types_ko) {
    auto no_bss_rental_json = R"(
        {
          "poi_types": [
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(no_bss_rental_json), std::invalid_argument);
    auto no_parking_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(no_parking_json), std::invalid_argument);
}

/*
 * poi-type id can't be defined twice
 */
BOOST_AUTO_TEST_CASE(double_poi_types_ko) {
    auto json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:bicycle_rental", "name": "BSS station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), std::invalid_argument);
}

/*
 * can't use a poi-type id that's not defined
 */
BOOST_AUTO_TEST_CASE(undefined_poi_type_ko) {
    auto json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "leisure", "value": "park"}
              ],
              "poi_type_id": "leisure:park"
            }
          ]
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), std::invalid_argument);
}

/*
 * can't provide an empty json, or an ill-formed json
 */
BOOST_AUTO_TEST_CASE(ill_json_poi_type_ko) {
    auto json = R"({})";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), boost::property_tree::ptree_bad_path);
    auto ill_json = R"(
        {
          "poi_types":
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          "rules": [
            {
              non-sense!!!!!
          ]
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(ill_json),
                      boost::property_tree::json_parser::json_parser_error);
}

/*
 * default tagging: check that default parameters chooses the good tag
 */
BOOST_AUTO_TEST_CASE(default_tagging) {
    auto default_json = ed::connectors::DEFAULT_JSON_POI_TYPES;
    const ed::connectors::PoiTypeParams params(default_json);

    BOOST_CHECK(params.get_applicable_poi_rule({}) == nullptr);
    BOOST_CHECK_EQUAL(params.get_applicable_poi_rule({{"amenity", "parking"}})->poi_type_id, "amenity:parking");
    BOOST_CHECK_EQUAL(params.get_applicable_poi_rule({{"leisure", "garden"}})->poi_type_id, "leisure:garden");
}

/*
 * multiple matches tagging: check that first matches
 */
BOOST_AUTO_TEST_CASE(multiple_match_tagging) {
    auto velib_prior_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "velib", "name": "Velib Station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"},
                {"key": "bss_type", "value": "velib"}
              ],
              "poi_type_id": "velib"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams velib_prior_params(velib_prior_json);
    auto bss_prior_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "velib", "name": "Velib Station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"},
                {"key": "bss_type", "value": "velib"}
              ],
              "poi_type_id": "velib"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams bss_prior_params(bss_prior_json);

    CanalTP::Tags velib_tags = {{"amenity", "bicycle_rental"}, {"bss_type", "velib"}};
    CanalTP::Tags bss_tags = {{"amenity", "bicycle_rental"}, {"bss_type", "unknown"}};

    BOOST_CHECK_EQUAL(velib_prior_params.get_applicable_poi_rule(velib_tags)->poi_type_id, "velib");
    BOOST_CHECK_EQUAL(bss_prior_params.get_applicable_poi_rule(velib_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(velib_prior_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(bss_prior_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
}

/*
 * `:` bug test (we can use an osm-tag key or osm-tag value that contains a colon)
 */
BOOST_AUTO_TEST_CASE(colon_tagging) {
    auto colon_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity:bicycle_rental", "value": "true"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "parking:effia"}
              ],
              "poi_type_id": "amenity:parking"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams colon_params(colon_json);

    CanalTP::Tags bss_tags = {{"amenity:bicycle_rental", "true"}};
    CanalTP::Tags effia_tags = {{"amenity", "parking:effia"}};

    BOOST_CHECK_EQUAL(colon_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(colon_params.get_applicable_poi_rule(effia_tags)->poi_type_id, "amenity:parking");
}
<commit_msg>Mask highway=trunk, trunk_link, motorway, motorway_link at autocomplete<commit_after>/* Copyright © 2001-2016, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

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

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "ed/data.h"
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE test_ed
#include <boost/test/unit_test.hpp>
#include <boost/property_tree/exceptions.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "conf.h"
#include "ed/build_helper.h"
#include "ed/connectors/osm_tags_reader.h"
#include "ed/default_poi_types.h"
#include "tests/utils_test.h"

struct logger_initialized {
    logger_initialized() { navitia::init_logger(); }
};
BOOST_GLOBAL_FIXTURE(logger_initialized);

/*
 * default poi-types and minimal json should be ok
 */
BOOST_AUTO_TEST_CASE(def_json_poi_types_ok) {
    auto default_json = ed::connectors::DEFAULT_JSON_POI_TYPES;
    BOOST_CHECK_NO_THROW(const ed::connectors::PoiTypeParams params(default_json));
    auto minimal_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_NO_THROW(const ed::connectors::PoiTypeParams params(minimal_json));
}

/*
 * poi-type parking and bss-rental are mandatory (used by kraken)
 */
BOOST_AUTO_TEST_CASE(no_parking_json_poi_types_ko) {
    auto no_bss_rental_json = R"(
        {
          "poi_types": [
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(no_bss_rental_json), std::invalid_argument);
    auto no_parking_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(no_parking_json), std::invalid_argument);
}

/*
 * poi-type id can't be defined twice
 */
BOOST_AUTO_TEST_CASE(double_poi_types_ko) {
    auto json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:bicycle_rental", "name": "BSS station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": []
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), std::invalid_argument);
}

/*
 * can't use a poi-type id that's not defined
 */
BOOST_AUTO_TEST_CASE(undefined_poi_type_ko) {
    auto json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "leisure", "value": "park"}
              ],
              "poi_type_id": "leisure:park"
            }
          ]
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), std::invalid_argument);
}

/*
 * can't provide an empty json, or an ill-formed json
 */
BOOST_AUTO_TEST_CASE(ill_json_poi_type_ko) {
    auto json = R"({})";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(json), boost::property_tree::ptree_bad_path);
    auto ill_json = R"(
        {
          "poi_types":
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          "rules": [
            {
              non-sense!!!!!
          ]
        })";
    BOOST_CHECK_THROW(const ed::connectors::PoiTypeParams params(ill_json),
                      boost::property_tree::json_parser::json_parser_error);
}

/*
 * default tagging: check that default parameters chooses the good tag
 */
BOOST_AUTO_TEST_CASE(default_tagging) {
    auto default_json = ed::connectors::DEFAULT_JSON_POI_TYPES;
    const ed::connectors::PoiTypeParams params(default_json);

    BOOST_CHECK(params.get_applicable_poi_rule({}) == nullptr);
    BOOST_CHECK_EQUAL(params.get_applicable_poi_rule({{"amenity", "parking"}})->poi_type_id, "amenity:parking");
    BOOST_CHECK_EQUAL(params.get_applicable_poi_rule({{"leisure", "garden"}})->poi_type_id, "leisure:garden");
}

/*
 * multiple matches tagging: check that first matches
 */
BOOST_AUTO_TEST_CASE(multiple_match_tagging) {
    auto velib_prior_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "velib", "name": "Velib Station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"},
                {"key": "bss_type", "value": "velib"}
              ],
              "poi_type_id": "velib"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams velib_prior_params(velib_prior_json);
    auto bss_prior_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "velib", "name": "Velib Station"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "bicycle_rental"},
                {"key": "bss_type", "value": "velib"}
              ],
              "poi_type_id": "velib"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams bss_prior_params(bss_prior_json);

    CanalTP::Tags velib_tags = {{"amenity", "bicycle_rental"}, {"bss_type", "velib"}};
    CanalTP::Tags bss_tags = {{"amenity", "bicycle_rental"}, {"bss_type", "unknown"}};

    BOOST_CHECK_EQUAL(velib_prior_params.get_applicable_poi_rule(velib_tags)->poi_type_id, "velib");
    BOOST_CHECK_EQUAL(bss_prior_params.get_applicable_poi_rule(velib_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(velib_prior_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(bss_prior_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
}

/*
 * `:` bug test (we can use an osm-tag key or osm-tag value that contains a colon)
 */
BOOST_AUTO_TEST_CASE(colon_tagging) {
    auto colon_json = R"(
        {
          "poi_types": [
            {"id": "amenity:bicycle_rental", "name": "Station VLS"},
            {"id": "amenity:parking", "name": "Parking"}
          ],
          "rules": [
            {
              "osm_tags_filters": [
                {"key": "amenity:bicycle_rental", "value": "true"}
              ],
              "poi_type_id": "amenity:bicycle_rental"
            },
            {
              "osm_tags_filters": [
                {"key": "amenity", "value": "parking:effia"}
              ],
              "poi_type_id": "amenity:parking"
            }
          ]
        })";
    const ed::connectors::PoiTypeParams colon_params(colon_json);

    CanalTP::Tags bss_tags = {{"amenity:bicycle_rental", "true"}};
    CanalTP::Tags effia_tags = {{"amenity", "parking:effia"}};

    BOOST_CHECK_EQUAL(colon_params.get_applicable_poi_rule(bss_tags)->poi_type_id, "amenity:bicycle_rental");
    BOOST_CHECK_EQUAL(colon_params.get_applicable_poi_rule(effia_tags)->poi_type_id, "amenity:parking");
}

BOOST_AUTO_TEST_CASE(highway_trunk_not_visible) {
    std::bitset<8> res = ed::connectors::parse_way_tags({{"highway", "trunk"}});
    BOOST_CHECK_EQUAL(res[ed::connectors::VISIBLE], false);
}

BOOST_AUTO_TEST_CASE(highway_trunk_link_not_visible) {
    std::bitset<8> res = ed::connectors::parse_way_tags({{"highway", "trunk_link"}});
    BOOST_CHECK_EQUAL(res[ed::connectors::VISIBLE], false);
}

BOOST_AUTO_TEST_CASE(highway_motorway_not_visible) {
    std::bitset<8> res = ed::connectors::parse_way_tags({{"highway", "motorway"}});
    BOOST_CHECK_EQUAL(res[ed::connectors::VISIBLE], false);
}

BOOST_AUTO_TEST_CASE(highway_motorway_link_not_visible) {
    std::bitset<8> res = ed::connectors::parse_way_tags({{"highway", "motorway_link"}});
    BOOST_CHECK_EQUAL(res[ed::connectors::VISIBLE], false);
}

BOOST_AUTO_TEST_CASE(highway_cycleway_visible) {
    std::bitset<8> res = ed::connectors::parse_way_tags({{"highway", "cycleway"}});
    BOOST_CHECK_EQUAL(res[ed::connectors::VISIBLE], true);
}
<|endoftext|>


<commit_before>#include <exception>
#include <memory>
#include <functional>
#include <algorithm>

namespace crashes {

	typedef std::function<void (int)> on_feedback;

	namespace detail {

		//////////////////////////////////////////////
		typedef std::shared_ptr<size_t> shared_number;

		////////////////////
		class simple_count {
			size_t copy_nr;
		public:

			simple_count():copy_nr(0){}

			size_t get_copy_nr() const {
				return copy_nr;
			}

			void increment() {
				++copy_nr;
			}

			bool should_have_crashed_on(size_t) {
				return false;
			}
		};

		////////////////////////////////////////////
		template <typename TSharedInt=shared_number>
		class shared_count {
			TSharedInt copy_nr;

		public:

			shared_count():copy_nr(new size_t(0)){}

			size_t get_copy_nr() const {
				return *copy_nr;
			}

			void increment() {
				++(*copy_nr);
			}

			bool should_have_crashed_on(size_t) {
				return false;
			}
		};

		/////////////////////
		template <typename T>
		class total_count
		{
			static size_t count_nr;

		public:

			total_count()
			{
				increment();
			}

			size_t get_copy_nr() const {
				return count_nr;
			}

			void increment() {
				++count_nr;
			}

			bool should_have_crashed_on(size_t N) {
				return count_nr>=N;
			}

		//protected:

			~total_count()
			{
				--count_nr;
			}
		};
		template <typename T> size_t total_count<T>::count_nr(0);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		template <size_t MaxN,typename TFeedback=on_feedback, typename TCounter=simple_count>
		struct when {
			class copies {
				TCounter counter;
				TFeedback feedback;
			public:

				copies() {
					if (counter.should_have_crashed_on(MaxN))
						throw std::runtime_error("illegal number of copies");
				}

				virtual ~copies() {} //todo: review

				copies(const copies& other):
					counter(other.counter),
					feedback(other.feedback)
				{
					counter.increment();
					size_t count=counter.get_copy_nr();
					if (feedback)
						feedback(count);
					if (count>=MaxN)
						throw std::runtime_error("illegal number of copies");
				}

				copies& operator=(copies const& other)  {
					copies tmp(other);
					swap(other);
					return *this;
				}

				void swap(copies const& other) {
					std::swap(counter,other.counter);
					std::swap(feedback,other.feedback);
				}

			public:

				void set_feedback(TFeedback const& f) {
					feedback=f;
				}

			};
			typedef copies copy;
		};
	}

	/// crashes on MaxN total number of copies
	template <size_t MaxN>
	struct on : public detail::when<MaxN,on_feedback,detail::shared_count<detail::shared_number>>
	{};

	/// crashes on MaxN'th copy
	template <size_t MaxN>
	struct after : public detail::when<MaxN,on_feedback,detail::simple_count>
	{};

	/// crashes on MaxN total instances of T
	template <size_t MaxN,typename T>
	struct on_total : public detail::when<MaxN,on_feedback,detail::total_count<T>>
	{
		typedef copies instances;
		typedef copies instance;
	};
}<commit_msg>total_count decrement configurable<commit_after>#include <exception>
#include <memory>
#include <functional>
#include <algorithm>

namespace crashes {

	typedef std::function<void (int)> on_feedback;

	namespace detail {

		//////////////////////////////////////////////
		typedef std::shared_ptr<size_t> shared_number;

		////////////////////
		class simple_count {
			size_t copy_nr;
		public:

			simple_count():copy_nr(0){}

			size_t get_copy_nr() const {
				return copy_nr;
			}

			void increment() {
				++copy_nr;
			}

			bool should_have_crashed_on(size_t) {
				return false;
			}
		};

		////////////////////////////////////////////
		template <typename TSharedInt=shared_number>
		class shared_count {
			TSharedInt copy_nr;

		public:

			shared_count():copy_nr(new size_t(0)){}

			size_t get_copy_nr() const {
				return *copy_nr;
			}

			void increment() {
				++(*copy_nr);
			}

			bool should_have_crashed_on(size_t) {
				return false;
			}
		};

		////////////////////////////////////////
		struct should_decrement_on_destruction {
			static const bool should_decrement=true;
		};

		//////////////////////////////////////////
		struct shouldnt_decrement_on_destruction {
			static const bool should_decrement=false;
		};

		/////////////////////
		template <typename T,typename TDecrement>
		class total_count
		{
			static size_t count_nr;

		public:

			total_count()
			{
				increment();
			}

			size_t get_copy_nr() const {
				return count_nr;
			}

			void increment() {
				++count_nr;
			}

			bool should_have_crashed_on(size_t N) {
				return count_nr>=N;
			}

			//protected:

			~total_count()
			{
				if (TDecrement::should_decrement)
					--count_nr;
			}
		};
		template <typename T,typename TDecrement> size_t total_count<T,TDecrement>::count_nr(0);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		template <size_t MaxN,typename TFeedback=on_feedback, typename TCounter=simple_count>
		struct when {
			class copies {
				TCounter counter;
				TFeedback feedback;
			public:

				copies() {
					if (counter.should_have_crashed_on(MaxN))
						throw std::runtime_error("illegal number of copies");
				}

				virtual ~copies() {} //todo: review

				copies(const copies& other):
					counter(other.counter),
					feedback(other.feedback)
				{
					counter.increment();
					size_t count=counter.get_copy_nr();
					if (feedback)
						feedback(count);
					if (count>=MaxN)
						throw std::runtime_error("illegal number of copies");
				}

				copies& operator=(copies const& other)  {
					copies tmp(other);
					swap(other);
					return *this;
				}

				void swap(copies const& other) {
					std::swap(counter,other.counter);
					std::swap(feedback,other.feedback);
				}

			public:

				void set_feedback(TFeedback const& f) {
					feedback=f;
				}

			};
			typedef copies copy;
		};
	}

	/// crashes on MaxN total number of copies
	template <size_t MaxN>
	struct on : public detail::when<MaxN,on_feedback,detail::shared_count<detail::shared_number>>
	{};

	/// crashes on MaxN'th copy
	template <size_t MaxN>
	struct after : public detail::when<MaxN,on_feedback,detail::simple_count>
	{};

	/// crashes on MaxN total instances of T
	template <size_t MaxN,typename T>
	struct on_total : public detail::when<MaxN,on_feedback,detail::total_count<T,detail::should_decrement_on_destruction>>
	{
		typedef copies instances;
		typedef copies instance;
	};
}<|endoftext|>


<commit_before>#include "face_registry.hh"

#include "containers.hh"
#include "exception.hh"
#include "containers.hh"

namespace Kakoune
{

static Face parse_face(StringView facedesc)
{
    auto bg_it = find(facedesc, ',');
    auto attr_it = find(facedesc, '+');
    if (bg_it != facedesc.end() and attr_it < bg_it)
        throw runtime_error("invalid face description, expected <fg>[,<bg>][+<attr>]");
    Face res;
    res.fg = str_to_color({facedesc.begin(), std::min(attr_it, bg_it)});
    if (bg_it != facedesc.end())
        res.bg = str_to_color({bg_it+1, attr_it});
    if (attr_it != facedesc.end())
    {
        for (++attr_it; attr_it != facedesc.end(); ++attr_it)
        {
            switch (*attr_it)
            {
                case 'u': res.attributes |= Attribute::Underline; break;
                case 'r': res.attributes |= Attribute::Reverse; break;
                case 'b': res.attributes |= Attribute::Bold; break;
                case 'B': res.attributes |= Attribute::Blink; break;
                case 'd': res.attributes |= Attribute::Dim; break;
                default: throw runtime_error(format("unknown face attribute '{}'", StringView{*attr_it}));
            }
        }
    }
    return res;
}

Face FaceRegistry::operator[](const String& facedesc)
{
    auto it = m_aliases.find(facedesc);
    while (it != m_aliases.end())
    {
        if (it->second.alias.empty())
            return it->second.face;
        it = m_aliases.find(it->second.alias);
    }
    return parse_face(facedesc);
}

void FaceRegistry::register_alias(const String& name, const String& facedesc,
                                  bool override)
{
    if (not override and m_aliases.find(name) != m_aliases.end())
        throw runtime_error(format("alias '{}' already defined", name));

    if (name.empty() or is_color_name(name) or
        std::any_of(name.begin(), name.end(),
                    [](char c){ return not isalnum(c); }))
        throw runtime_error(format("invalid alias name: '{}'", name));

    FaceOrAlias& alias = m_aliases[name];
    auto it = m_aliases.find(facedesc);
    if (it != m_aliases.end())
    {
        while (it != m_aliases.end())
        {
            if (it->second.alias.empty())
                break;
            if (it->second.alias == name)
                throw runtime_error("face cycle detected");
            it = m_aliases.find(it->second.alias);
        }

        alias.alias = facedesc;
    }
    else
    {
        alias.alias = "";
        alias.face = parse_face(facedesc);
    }
}

CandidateList FaceRegistry::complete_alias_name(StringView prefix,
                                                ByteCount cursor_pos) const
{
    using ValueType = std::pair<String, FaceOrAlias>;
    return complete(prefix, cursor_pos,
                    transformed(m_aliases,
                                [](const ValueType& v){ return v.first; }));
}

FaceRegistry::FaceRegistry()
    : m_aliases{
        { "Default", Face{ Color::Default, Color::Default } },
        { "PrimarySelection", Face{ Color::White, Color::Blue } },
        { "SecondarySelection", Face{ Color::Black, Color::Blue } },
        { "PrimaryCursor", Face{ Color::Black, Color::White } },
        { "SecondaryCursor", Face{ Color::Black, Color::White } },
        { "LineNumbers", Face{ Color::Default, Color::Default } },
        { "LineNumberCursor", Face{ Color::Default, Color::Default, Attribute::Reverse } },
        { "MenuForeground", Face{ Color::White, Color::Blue } },
        { "MenuBackground", Face{ Color::Blue, Color::White } },
        { "Information", Face{ Color::Black, Color::Yellow } },
        { "Error", Face{ Color::Black, Color::Red } },
        { "StatusLine", Face{ Color::Cyan, Color::Default } },
        { "StatusCursor", Face{ Color::Black, Color::Cyan } },
        { "Prompt", Face{ Color::Yellow, Color::Default } },
        { "MatchingChar", Face{ Color::Default, Color::Default, Attribute::Bold } },
        { "Search", Face{ Color::Default, Color::Default, Attribute::Underline } },
      }
{}

}
<commit_msg>Detect face being aliased to itself<commit_after>#include "face_registry.hh"

#include "containers.hh"
#include "exception.hh"
#include "containers.hh"

namespace Kakoune
{

static Face parse_face(StringView facedesc)
{
    auto bg_it = find(facedesc, ',');
    auto attr_it = find(facedesc, '+');
    if (bg_it != facedesc.end() and attr_it < bg_it)
        throw runtime_error("invalid face description, expected <fg>[,<bg>][+<attr>]");
    Face res;
    res.fg = str_to_color({facedesc.begin(), std::min(attr_it, bg_it)});
    if (bg_it != facedesc.end())
        res.bg = str_to_color({bg_it+1, attr_it});
    if (attr_it != facedesc.end())
    {
        for (++attr_it; attr_it != facedesc.end(); ++attr_it)
        {
            switch (*attr_it)
            {
                case 'u': res.attributes |= Attribute::Underline; break;
                case 'r': res.attributes |= Attribute::Reverse; break;
                case 'b': res.attributes |= Attribute::Bold; break;
                case 'B': res.attributes |= Attribute::Blink; break;
                case 'd': res.attributes |= Attribute::Dim; break;
                default: throw runtime_error(format("unknown face attribute '{}'", StringView{*attr_it}));
            }
        }
    }
    return res;
}

Face FaceRegistry::operator[](const String& facedesc)
{
    auto it = m_aliases.find(facedesc);
    while (it != m_aliases.end())
    {
        if (it->second.alias.empty())
            return it->second.face;
        it = m_aliases.find(it->second.alias);
    }
    return parse_face(facedesc);
}

void FaceRegistry::register_alias(const String& name, const String& facedesc,
                                  bool override)
{
    if (not override and m_aliases.find(name) != m_aliases.end())
        throw runtime_error(format("alias '{}' already defined", name));

    if (name.empty() or is_color_name(name) or
        std::any_of(name.begin(), name.end(),
                    [](char c){ return not isalnum(c); }))
        throw runtime_error(format("invalid alias name: '{}'", name));

    if (name == facedesc)
        throw runtime_error(format("cannot alias face '{}' to itself", name));

    FaceOrAlias& alias = m_aliases[name];
    auto it = m_aliases.find(facedesc);
    if (it != m_aliases.end())
    {
        while (it != m_aliases.end())
        {
            if (it->second.alias.empty())
                break;
            if (it->second.alias == name)
                throw runtime_error("face cycle detected");
            it = m_aliases.find(it->second.alias);
        }

        alias.alias = facedesc;
    }
    else
    {
        alias.alias = "";
        alias.face = parse_face(facedesc);
    }
}

CandidateList FaceRegistry::complete_alias_name(StringView prefix,
                                                ByteCount cursor_pos) const
{
    using ValueType = std::pair<String, FaceOrAlias>;
    return complete(prefix, cursor_pos,
                    transformed(m_aliases,
                                [](const ValueType& v){ return v.first; }));
}

FaceRegistry::FaceRegistry()
    : m_aliases{
        { "Default", Face{ Color::Default, Color::Default } },
        { "PrimarySelection", Face{ Color::White, Color::Blue } },
        { "SecondarySelection", Face{ Color::Black, Color::Blue } },
        { "PrimaryCursor", Face{ Color::Black, Color::White } },
        { "SecondaryCursor", Face{ Color::Black, Color::White } },
        { "LineNumbers", Face{ Color::Default, Color::Default } },
        { "LineNumberCursor", Face{ Color::Default, Color::Default, Attribute::Reverse } },
        { "MenuForeground", Face{ Color::White, Color::Blue } },
        { "MenuBackground", Face{ Color::Blue, Color::White } },
        { "Information", Face{ Color::Black, Color::Yellow } },
        { "Error", Face{ Color::Black, Color::Red } },
        { "StatusLine", Face{ Color::Cyan, Color::Default } },
        { "StatusCursor", Face{ Color::Black, Color::Cyan } },
        { "Prompt", Face{ Color::Yellow, Color::Default } },
        { "MatchingChar", Face{ Color::Default, Color::Default, Attribute::Bold } },
        { "Search", Face{ Color::Default, Color::Default, Attribute::Underline } },
      }
{}

}
<|endoftext|>


<commit_before><commit_msg>fixed: wrote atom names containing whitespaces and could no longer read those<commit_after><|endoftext|>


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

#include "processcontrol.h"

#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtDebug>

#ifdef Q_OS_UNIX
#include <sys/types.h>
#include <signal.h>
#endif

using namespace Akonadi;

ProcessControl::ProcessControl( QObject *parent )
  : QObject( parent ), mFailedToStart( false ), mCrashCount( 0 ),
  mRestartOnceOnExit( false )
{
  connect( &mProcess, SIGNAL( error( QProcess::ProcessError ) ),
           this, SLOT( slotError( QProcess::ProcessError ) ) );
  connect( &mProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
           this, SLOT( slotFinished( int, QProcess::ExitStatus ) ) );
  connect( &mProcess, SIGNAL( readyReadStandardError() ),
           this, SLOT( slotErrorMessages() ) );
  connect( &mProcess, SIGNAL( readyReadStandardOutput() ),
            this, SLOT( slotStdoutMessages() ) );
}

ProcessControl::~ProcessControl()
{
  stop();
}

void ProcessControl::start( const QString &application, const QStringList &arguments, CrashPolicy policy )
{
  mFailedToStart = false;

  mApplication = application;
  mArguments = arguments;
  mPolicy = policy;

  start();
}

void ProcessControl::setCrashPolicy( CrashPolicy policy )
{
  mPolicy = policy;
}

void ProcessControl::stop()
{
  if ( mProcess.state() != QProcess::NotRunning ) {
    mProcess.waitForFinished( 10000 );
    mProcess.terminate();
  }
}

void ProcessControl::slotError( QProcess::ProcessError error )
{
  switch ( error ) {
    case QProcess::Crashed:
      // do nothing, we'll respawn in slotFinished
      break;
    case QProcess::FailedToStart:
    default:
        mFailedToStart = true;
      break;
  }

  qDebug( "ProcessControl: Application '%s' stopped unexpected (%s)",
          qPrintable( mApplication ), qPrintable( mProcess.errorString() ) );
}

void ProcessControl::slotFinished( int exitCode, QProcess::ExitStatus exitStatus )
{
  if ( exitStatus == QProcess::CrashExit ) {
    if ( mPolicy == RestartOnCrash ) {
      if ( !mFailedToStart ) // don't try to start an unstartable application
        start();
    }
  } else {
    if ( exitCode != 0 ) {
      qDebug( "ProcessControl: Application '%s' returned with exit code %d (%s)",
              qPrintable( mApplication ), exitCode, qPrintable( mProcess.errorString() ) );
      if ( mPolicy == RestartOnCrash ) {
        if ( mCrashCount > 2 ) {
          qWarning() << mApplication << "crashed too often and will not be restarted!";
          mPolicy = StopOnCrash;
          emit unableToStart();
          return;
        }
        ++mCrashCount;
        QTimer::singleShot( 60000, this, SLOT(resetCrashCount()) );
        if ( !mFailedToStart ) // don't try to start an unstartable application
          start();
      }
    } else {
      if ( mRestartOnceOnExit ) {
        mRestartOnceOnExit = false;
        qDebug( "Restarting application '%s'.", qPrintable( mApplication ) );
        start();
      } else {
        qDebug( "Application '%s' exited normally...", qPrintable( mApplication ) );
      }
    }
  }
}

namespace {
  static QString getEnv( const char* name, const QString& defaultValue=QString() ) {
    const QString v = QString::fromLocal8Bit( qgetenv( name ) );
    return !v.isEmpty() ? v : defaultValue;
  }
}

void ProcessControl::start()
{
#ifdef Q_OS_UNIX
  QString agentValgrind = getEnv( "AKONADI_VALGRIND" );
  if ( !agentValgrind.isEmpty() && mApplication.contains( agentValgrind ) ) {

    mArguments.prepend( mApplication );
    mApplication = QString::fromLocal8Bit( "valgrind" );

    const QString valgrindSkin = getEnv( "AKONADI_VALGRIND_SKIN", QString::fromLocal8Bit( "memcheck" ) );
    mArguments.prepend( QLatin1String( "--tool=" ) + valgrindSkin );

    const QString valgrindOptions = getEnv( "AKONADI_VALGRIND_OPTIONS" );
    if ( !valgrindOptions.isEmpty() )
      mArguments = valgrindOptions.split( ' ' ) << mArguments;

    qDebug();
    qDebug() << "============================================================";
    qDebug() << "ProcessControl: Valgrinding process" << mApplication;
    if ( !valgrindSkin.isEmpty() )
      qDebug() << "ProcessControl: Valgrind skin:" << valgrindSkin;
    if ( !valgrindOptions.isEmpty() )
      qDebug() << "ProcessControl: Additional Valgrind options:" << valgrindOptions;
    qDebug() << "============================================================";
    qDebug();
  }
#endif

  mProcess.start( mApplication, mArguments );
  if ( !mProcess.waitForStarted( ) ) {
    qDebug( "ProcessControl: Unable to start application '%s' (%s)",
            qPrintable( mApplication ), qPrintable( mProcess.errorString() ) );
    return;
  }

#ifdef Q_OS_UNIX
  else {
    QString agentDebug = QString::fromLocal8Bit( qgetenv( "AKONADI_DEBUG_WAIT" ) );
    pid_t pid = mProcess.pid();
    if ( !agentDebug.isEmpty() && mApplication.contains( agentDebug ) ) {
      qDebug();
      qDebug() << "============================================================";
      qDebug() << "ProcessControl: Suspending process" << mApplication;
      qDebug() << "'gdb" << pid << "' to debug";
      qDebug() << "'kill -SIGCONT" << pid << "' to continue";
      qDebug() << "============================================================";
      qDebug();
      kill( pid, SIGSTOP );
    }
  }
#endif
}

void Akonadi::ProcessControl::slotStdoutMessages()
{
  mProcess.setReadChannel( QProcess::StandardOutput );
  while ( mProcess.canReadLine() ) {
    QString message = QString::fromUtf8( mProcess.readLine() );
    qDebug() << mApplication << "[out]" << message;
  }
}

void ProcessControl::slotErrorMessages()
{
  mProcess.setReadChannel( QProcess::StandardError );
  while ( mProcess.canReadLine() ) {
    QString message = QString::fromUtf8( mProcess.readLine() );
    emit processErrorMessages( message );
    qDebug( "[%s] %s", qPrintable( mApplication ), qPrintable( message.trimmed() ) );
  }
}

void ProcessControl::resetCrashCount()
{
  mCrashCount = 0;
}

#include "processcontrol.moc"
<commit_msg>Fix printing the process name which is being valgrinded.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "processcontrol.h"

#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtDebug>

#ifdef Q_OS_UNIX
#include <sys/types.h>
#include <signal.h>
#endif

using namespace Akonadi;

ProcessControl::ProcessControl( QObject *parent )
  : QObject( parent ), mFailedToStart( false ), mCrashCount( 0 ),
  mRestartOnceOnExit( false )
{
  connect( &mProcess, SIGNAL( error( QProcess::ProcessError ) ),
           this, SLOT( slotError( QProcess::ProcessError ) ) );
  connect( &mProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
           this, SLOT( slotFinished( int, QProcess::ExitStatus ) ) );
  connect( &mProcess, SIGNAL( readyReadStandardError() ),
           this, SLOT( slotErrorMessages() ) );
  connect( &mProcess, SIGNAL( readyReadStandardOutput() ),
            this, SLOT( slotStdoutMessages() ) );
}

ProcessControl::~ProcessControl()
{
  stop();
}

void ProcessControl::start( const QString &application, const QStringList &arguments, CrashPolicy policy )
{
  mFailedToStart = false;

  mApplication = application;
  mArguments = arguments;
  mPolicy = policy;

  start();
}

void ProcessControl::setCrashPolicy( CrashPolicy policy )
{
  mPolicy = policy;
}

void ProcessControl::stop()
{
  if ( mProcess.state() != QProcess::NotRunning ) {
    mProcess.waitForFinished( 10000 );
    mProcess.terminate();
  }
}

void ProcessControl::slotError( QProcess::ProcessError error )
{
  switch ( error ) {
    case QProcess::Crashed:
      // do nothing, we'll respawn in slotFinished
      break;
    case QProcess::FailedToStart:
    default:
        mFailedToStart = true;
      break;
  }

  qDebug( "ProcessControl: Application '%s' stopped unexpected (%s)",
          qPrintable( mApplication ), qPrintable( mProcess.errorString() ) );
}

void ProcessControl::slotFinished( int exitCode, QProcess::ExitStatus exitStatus )
{
  if ( exitStatus == QProcess::CrashExit ) {
    if ( mPolicy == RestartOnCrash ) {
      if ( !mFailedToStart ) // don't try to start an unstartable application
        start();
    }
  } else {
    if ( exitCode != 0 ) {
      qDebug( "ProcessControl: Application '%s' returned with exit code %d (%s)",
              qPrintable( mApplication ), exitCode, qPrintable( mProcess.errorString() ) );
      if ( mPolicy == RestartOnCrash ) {
        if ( mCrashCount > 2 ) {
          qWarning() << mApplication << "crashed too often and will not be restarted!";
          mPolicy = StopOnCrash;
          emit unableToStart();
          return;
        }
        ++mCrashCount;
        QTimer::singleShot( 60000, this, SLOT(resetCrashCount()) );
        if ( !mFailedToStart ) // don't try to start an unstartable application
          start();
      }
    } else {
      if ( mRestartOnceOnExit ) {
        mRestartOnceOnExit = false;
        qDebug( "Restarting application '%s'.", qPrintable( mApplication ) );
        start();
      } else {
        qDebug( "Application '%s' exited normally...", qPrintable( mApplication ) );
      }
    }
  }
}

namespace {
  static QString getEnv( const char* name, const QString& defaultValue=QString() ) {
    const QString v = QString::fromLocal8Bit( qgetenv( name ) );
    return !v.isEmpty() ? v : defaultValue;
  }
}

void ProcessControl::start()
{
#ifdef Q_OS_UNIX
  QString agentValgrind = getEnv( "AKONADI_VALGRIND" );
  if ( !agentValgrind.isEmpty() && mApplication.contains( agentValgrind ) ) {

    mArguments.prepend( mApplication );
    const QString originalArguments = mArguments.join( QString::fromLocal8Bit( " " ) );
    mApplication = QString::fromLocal8Bit( "valgrind" );

    const QString valgrindSkin = getEnv( "AKONADI_VALGRIND_SKIN", QString::fromLocal8Bit( "memcheck" ) );
    mArguments.prepend( QLatin1String( "--tool=" ) + valgrindSkin );

    const QString valgrindOptions = getEnv( "AKONADI_VALGRIND_OPTIONS" );
    if ( !valgrindOptions.isEmpty() )
      mArguments = valgrindOptions.split( ' ' ) << mArguments;

    qDebug();
    qDebug() << "============================================================";
    qDebug() << "ProcessControl: Valgrinding process" << originalArguments;
    if ( !valgrindSkin.isEmpty() )
      qDebug() << "ProcessControl: Valgrind skin:" << valgrindSkin;
    if ( !valgrindOptions.isEmpty() )
      qDebug() << "ProcessControl: Additional Valgrind options:" << valgrindOptions;
    qDebug() << "============================================================";
    qDebug();
  }
#endif

  mProcess.start( mApplication, mArguments );
  if ( !mProcess.waitForStarted( ) ) {
    qDebug( "ProcessControl: Unable to start application '%s' (%s)",
            qPrintable( mApplication ), qPrintable( mProcess.errorString() ) );
    return;
  }

#ifdef Q_OS_UNIX
  else {
    QString agentDebug = QString::fromLocal8Bit( qgetenv( "AKONADI_DEBUG_WAIT" ) );
    pid_t pid = mProcess.pid();
    if ( !agentDebug.isEmpty() && mApplication.contains( agentDebug ) ) {
      qDebug();
      qDebug() << "============================================================";
      qDebug() << "ProcessControl: Suspending process" << mApplication;
      qDebug() << "'gdb" << pid << "' to debug";
      qDebug() << "'kill -SIGCONT" << pid << "' to continue";
      qDebug() << "============================================================";
      qDebug();
      kill( pid, SIGSTOP );
    }
  }
#endif
}

void Akonadi::ProcessControl::slotStdoutMessages()
{
  mProcess.setReadChannel( QProcess::StandardOutput );
  while ( mProcess.canReadLine() ) {
    QString message = QString::fromUtf8( mProcess.readLine() );
    qDebug() << mApplication << "[out]" << message;
  }
}

void ProcessControl::slotErrorMessages()
{
  mProcess.setReadChannel( QProcess::StandardError );
  while ( mProcess.canReadLine() ) {
    QString message = QString::fromUtf8( mProcess.readLine() );
    emit processErrorMessages( message );
    qDebug( "[%s] %s", qPrintable( mApplication ), qPrintable( message.trimmed() ) );
  }
}

void ProcessControl::resetCrashCount()
{
  mCrashCount = 0;
}

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


<commit_before>#include <GLXW/glxw.h>
#include <GLFW/glfw3.h>
#include <checks.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "dcpurenderer.hpp"

namespace dcpu {

  void DcpuRenderer::Change(int width, int height) {
    glViewport(0, 0, width, height);
    auto aspect = static_cast<float>(width) / height;
    projection = glm::frustum(-0.1f * aspect, 0.1f * aspect, -0.1f, 0.1f, 0.1f, 1000.0f);
  }

  void DcpuRenderer::Create() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glEnable(GL_BLEND);
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    // glLineWidth(2.0f);

    vertex_shader.CreateFromFile(GL_VERTEX_SHADER, "source/vertex.glsl");
    fragment_shader.CreateFromFile(GL_FRAGMENT_SHADER, "source/fragment.glsl");
    program.Create({&vertex_shader, &fragment_shader});
    program.CompileAndLink();
    vertex_format.Create({
      {"vertex_position", GL_FLOAT, 3},
      {"vertex_color", GL_FLOAT, 4}
    });

    beam_buffer.Create(GL_ARRAY_BUFFER);
    beam_vertex_array.Create();
    vertex_format.Apply(beam_vertex_array, program);

    line_buffer.Create(GL_ARRAY_BUFFER);
    line_vertex_array.Create();
    vertex_format.Apply(line_vertex_array, program);

    CHECK_STATE(!glGetError());

    dcpu.Connect(&display);

    model_view = glm::mat4(
      1.0f, 0.0f, 0.0f, 0.0f,
      0.0f, 1.0f, 0.0f, 0.0f,
      0.0f, 0.0f, 1.0f, 0.0f,
      0.0f, -0.8f, -1.5f, 1.0f
    );
  }

  void DcpuRenderer::Render() {
    Update();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    program.Use();
    program.UniformsMatrix4f({
      {"model_view", &model_view},
      {"projection", &projection}
    });

    auto beam_drawable = display.BeamView();
    beam_buffer.Data(beam_drawable.data_size(), beam_drawable.data.data(), GL_STREAM_DRAW);
    beam_vertex_array.Bind();
    glDrawArrays(beam_drawable.element_type, 0, beam_drawable.element_count);

    auto line_drawable = display.LineView();
    line_buffer.Data(line_drawable.data_size(), line_drawable.data.data(), GL_STREAM_DRAW);
    line_vertex_array.Bind();
    glDrawArrays(line_drawable.element_type, 0, line_drawable.element_count);

    CHECK_STATE(!glGetError());
  }

  void DcpuRenderer::Update() {
    // dcpu.ExecuteInstructions(1666);
    display.Execute();

    x += vx;
    y += vy;
    z += vz;
    if (x < 0) {
      x = 0;
      vx *= -1;
    }
    if (x > 223) {
      x = 223;
      vx *= -1;
    }if (y < 0) {
      y = 0;
      vy *= -1;
    }
    if (y > 223) {
      y = 223;
      vy *= -1;
    }
    if (z < 0) {
      z = 0;
      vz *= -1;
    }
    if (z > 223) {
      z = 223;
      vz *= -1;
    }
    Word word0 = (y << 8) | x;
    Word word1 = z;
    auto data = {
      0x0000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0700 + word1,
      0x2020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0700 + word1,
      0x0000 + word0, 0x0700 + word1,

      0x0000 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0720 + word1,

      0x0000 + word0, 0x0720 + word1,
      0x2000 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0720 + word1,
      0x0020 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0020 + word1,

      0x3000 + word0, 0x0000 + word1,
      0x3000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0700 + word1,
      0x5020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0700 + word1,
      0x3000 + word0, 0x0700 + word1,

      0x3000 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0720 + word1,

      0x3000 + word0, 0x0720 + word1,
      0x5000 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0720 + word1,
      0x3020 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0020 + word1,

      0x0000, 0x0000,
      0x0000, 0x0700,
      0x2000, 0x0700,
      0x2000, 0x0000,
      0xDF00, 0x0000,
      0xDF00, 0x0700,
      0xFF00, 0x0700,
      0xFF20, 0x0700,
      0xFF20, 0x0000,
      0xFFDF, 0x0000,
      0xFFDF, 0x0700,
      0xFFFF, 0x0700,
      0xDFFF, 0x0700,
      0xDFFF, 0x0000,
      0x20FF, 0x0000,
      0x20FF, 0x0700,
      0x00FF, 0x0700,
      0x00DF, 0x0700,
      0x00DF, 0x0000,
      0x0020, 0x0000,
      0x0020, 0x0700,
      0x0000, 0x0700,
      0x0000, 0x0000,

      0x0000, 0x00FF,
      0x0000, 0x07FF,
      0x2000, 0x07FF,
      0x2000, 0x00FF,
      0xDF00, 0x00FF,
      0xDF00, 0x07FF,
      0xFF00, 0x07FF,
      0xFF20, 0x07FF,
      0xFF20, 0x00FF,
      0xFFDF, 0x00FF,
      0xFFDF, 0x07FF,
      0xFFFF, 0x07FF,
      0xDFFF, 0x07FF,
      0xDFFF, 0x00FF,
      0x20FF, 0x00FF,
      0x20FF, 0x07FF,
      0x00FF, 0x07FF,
      0x00DF, 0x07FF,
      0x00DF, 0x00FF,
      0x0020, 0x00FF,
      0x0020, 0x07FF,
      0x0000, 0x07FF
    };
    std::copy(data.begin(), data.end(), dcpu.memory_begin());
    display.Map(0, data.size() / 2);
  }
}
<commit_msg>Add a TODO.<commit_after>#include <GLXW/glxw.h>
#include <GLFW/glfw3.h>
#include <checks.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "dcpurenderer.hpp"

namespace dcpu {

  void DcpuRenderer::Change(int width, int height) {
    glViewport(0, 0, width, height);
    auto aspect = static_cast<float>(width) / height;
    projection = glm::frustum(-0.1f * aspect, 0.1f * aspect, -0.1f, 0.1f, 0.1f, 1000.0f);
  }

  void DcpuRenderer::Create() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glEnable(GL_BLEND);
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    // glLineWidth(2.0f);

    vertex_shader.CreateFromFile(GL_VERTEX_SHADER, "source/vertex.glsl");
    fragment_shader.CreateFromFile(GL_FRAGMENT_SHADER, "source/fragment.glsl");
    program.Create({&vertex_shader, &fragment_shader});
    program.CompileAndLink();
    vertex_format.Create({
      {"vertex_position", GL_FLOAT, 3},
      {"vertex_color", GL_FLOAT, 4}
    });

    beam_buffer.Create(GL_ARRAY_BUFFER);
    beam_vertex_array.Create();
    vertex_format.Apply(beam_vertex_array, program);

    line_buffer.Create(GL_ARRAY_BUFFER);
    line_vertex_array.Create();
    vertex_format.Apply(line_vertex_array, program);

    CHECK_STATE(!glGetError());

    dcpu.Connect(&display);

    model_view = glm::mat4(
      1.0f, 0.0f, 0.0f, 0.0f,
      0.0f, 1.0f, 0.0f, 0.0f,
      0.0f, 0.0f, 1.0f, 0.0f,
      0.0f, -0.8f, -1.5f, 1.0f
    );
  }

  void DcpuRenderer::Render() {
    Update();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    program.Use();
    program.UniformsMatrix4f({
      {"model_view", &model_view},
      {"projection", &projection}
    });

    auto beam_drawable = display.BeamView();
    beam_buffer.Data(beam_drawable.data_size(), beam_drawable.data.data(), GL_STREAM_DRAW);
    beam_vertex_array.Bind();
    glDrawArrays(beam_drawable.element_type, 0, beam_drawable.element_count);

    auto line_drawable = display.LineView();
    line_buffer.Data(line_drawable.data_size(), line_drawable.data.data(), GL_STREAM_DRAW);
    line_vertex_array.Bind();
    glDrawArrays(line_drawable.element_type, 0, line_drawable.element_count);

    CHECK_STATE(!glGetError());
  }

  void DcpuRenderer::Update() {
    // dcpu.ExecuteInstructions(1666);
    display.Execute();

    // TODO(robertsdionne): implement the logic in DCPU-16.
    x += vx;
    y += vy;
    z += vz;
    if (x < 0) {
      x = 0;
      vx *= -1;
    }
    if (x > 223) {
      x = 223;
      vx *= -1;
    }if (y < 0) {
      y = 0;
      vy *= -1;
    }
    if (y > 223) {
      y = 223;
      vy *= -1;
    }
    if (z < 0) {
      z = 0;
      vz *= -1;
    }
    if (z > 223) {
      z = 223;
      vz *= -1;
    }
    Word word0 = (y << 8) | x;
    Word word1 = z;
    auto data = {
      0x0000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0700 + word1,
      0x2020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0700 + word1,
      0x0000 + word0, 0x0700 + word1,

      0x0000 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0700 + word1,
      0x2000 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0700 + word1,
      0x0020 + word0, 0x0720 + word1,

      0x0000 + word0, 0x0720 + word1,
      0x2000 + word0, 0x0720 + word1,
      0x2020 + word0, 0x0720 + word1,
      0x0020 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0720 + word1,
      0x0000 + word0, 0x0020 + word1,

      0x3000 + word0, 0x0000 + word1,
      0x3000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0700 + word1,
      0x5020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0700 + word1,
      0x3000 + word0, 0x0700 + word1,

      0x3000 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0700 + word1,
      0x5000 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0700 + word1,
      0x3020 + word0, 0x0720 + word1,

      0x3000 + word0, 0x0720 + word1,
      0x5000 + word0, 0x0720 + word1,
      0x5020 + word0, 0x0720 + word1,
      0x3020 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0720 + word1,
      0x3000 + word0, 0x0020 + word1,

      0x0000, 0x0000,
      0x0000, 0x0700,
      0x2000, 0x0700,
      0x2000, 0x0000,
      0xDF00, 0x0000,
      0xDF00, 0x0700,
      0xFF00, 0x0700,
      0xFF20, 0x0700,
      0xFF20, 0x0000,
      0xFFDF, 0x0000,
      0xFFDF, 0x0700,
      0xFFFF, 0x0700,
      0xDFFF, 0x0700,
      0xDFFF, 0x0000,
      0x20FF, 0x0000,
      0x20FF, 0x0700,
      0x00FF, 0x0700,
      0x00DF, 0x0700,
      0x00DF, 0x0000,
      0x0020, 0x0000,
      0x0020, 0x0700,
      0x0000, 0x0700,
      0x0000, 0x0000,

      0x0000, 0x00FF,
      0x0000, 0x07FF,
      0x2000, 0x07FF,
      0x2000, 0x00FF,
      0xDF00, 0x00FF,
      0xDF00, 0x07FF,
      0xFF00, 0x07FF,
      0xFF20, 0x07FF,
      0xFF20, 0x00FF,
      0xFFDF, 0x00FF,
      0xFFDF, 0x07FF,
      0xFFFF, 0x07FF,
      0xDFFF, 0x07FF,
      0xDFFF, 0x00FF,
      0x20FF, 0x00FF,
      0x20FF, 0x07FF,
      0x00FF, 0x07FF,
      0x00DF, 0x07FF,
      0x00DF, 0x00FF,
      0x0020, 0x00FF,
      0x0020, 0x07FF,
      0x0000, 0x07FF
    };
    std::copy(data.begin(), data.end(), dcpu.memory_begin());
    display.Map(0, data.size() / 2);
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2003-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <log4cxx/fileappender.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/helpers/transcoder.h>
#include <apr_atomic.h>
#include <apr_file_io.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/helpers/aprinitializer.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;

IMPLEMENT_LOG4CXX_OBJECT(FileAppender)

FileAppender::FileAppender()
: fileAppend(true), fileName(), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName,
        bool append, bool bufferedIO, int bufferSize)
: fileAppend(append), fileName(fileName), bufferedIO(bufferedIO), bufferSize(bufferSize),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName,
        bool append)
: fileAppend(append), fileName(fileName), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName)
: fileAppend(true), fileName(fileName), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::~FileAppender()
{
    if (!APRInitializer::isDestructed) {
        finalize();
    }
}

void FileAppender::setFile(const File& file)
{
        fileName = file;
}

void FileAppender::setFile(const File& file, bool append,
        bool bufferedIO, int bufferSize) {
        fileName = file;
        fileAppend = append;
        this->bufferedIO = bufferedIO;
        this->bufferSize = bufferSize;
}

void FileAppender::closeWriter() {
    if (ofs != NULL) {
        apr_file_close(ofs);
        ofs = NULL;
    }
}

void FileAppender::setBufferedIO(bool bufferedIO)
{
        this->bufferedIO = bufferedIO;
        if(bufferedIO)
        {
                immediateFlush = false;
        }
}

void FileAppender::setOption(const LogString& option,
        const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILE"), LOG4CXX_STR("file"))
                || StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILENAME"), LOG4CXX_STR("filename")))
        {
                fileName = value;
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("APPEND"), LOG4CXX_STR("append")))
        {
                fileAppend = OptionConverter::toBoolean(value, true);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFEREDIO"), LOG4CXX_STR("bufferedio")))
        {
                bufferedIO = OptionConverter::toBoolean(value, true);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("IMMEDIATEFLUSH"), LOG4CXX_STR("immediateflush")))
        {
                bufferedIO = !OptionConverter::toBoolean(value, false);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFERSIZE"), LOG4CXX_STR("buffersize")))
        {
                bufferSize = OptionConverter::toFileSize(value, 8*1024);
        }
        else
        {
                WriterAppender::setOption(option, value);
        }
}

void FileAppender::activateOptions(Pool& p)
{
        if (fileName.getName().empty()) {
          LogLog::warn((LogString) LOG4CXX_STR("File option not set for appender [")
              + name + LOG4CXX_STR("]."));
          LogLog::warn(LOG4CXX_STR("Are you using FileAppender instead of ConsoleAppender?"));
        } else {
          synchronized sync(mutex);
          if (ofs != NULL) {
            LogLog::warn((LogString) LOG4CXX_STR("Appender [") +
                 name + LOG4CXX_STR("] already open."));
          }
          apr_fileperms_t perm = APR_OS_DEFAULT;
          apr_int32_t flags = APR_WRITE | APR_CREATE;
          if (fileAppend) {
            flags |= APR_APPEND;
          } else {
            flags |= APR_TRUNCATE;
          }
          if (bufferedIO) {
            flags |= APR_BUFFERED;
          }
          ofs = NULL;
          fileName.open(&ofs, flags, perm, pool);
          fileClosed = 0;
        }
        if (ofs != NULL) {
          writeHeader(p);
        }
}

void FileAppender::subAppend(const char* encoded, log4cxx_size_t size, Pool& p) {
  if (ofs != NULL) {
    apr_status_t rv = apr_file_write(ofs, encoded, &size);
    if (rv == APR_SUCCESS && immediateFlush) {
      rv = apr_file_flush(ofs);
    }
  }
}

<commit_msg>LOGCXX-58: Immediate flush'd FileAppenders extremely slow on Windows<commit_after>/*
 * Copyright 2003-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <log4cxx/fileappender.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/helpers/transcoder.h>
#include <apr_atomic.h>
#include <apr_file_io.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/helpers/aprinitializer.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;

IMPLEMENT_LOG4CXX_OBJECT(FileAppender)

FileAppender::FileAppender()
: fileAppend(true), fileName(), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName,
        bool append, bool bufferedIO, int bufferSize)
: fileAppend(append), fileName(fileName), bufferedIO(bufferedIO), bufferSize(bufferSize),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName,
        bool append)
: fileAppend(append), fileName(fileName), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::FileAppender(const LayoutPtr& layout, const File& fileName)
: fileAppend(true), fileName(fileName), bufferedIO(false), bufferSize(8*1024),
  pool(), ofs(NULL), fileClosed(1)
{
        this->layout = layout;
        Pool p;
        activateOptions(p);
}

FileAppender::~FileAppender()
{
    if (!APRInitializer::isDestructed) {
        finalize();
    }
}

void FileAppender::setFile(const File& file)
{
        fileName = file;
}

void FileAppender::setFile(const File& file, bool append,
        bool bufferedIO, int bufferSize) {
        fileName = file;
        fileAppend = append;
        this->bufferedIO = bufferedIO;
        this->bufferSize = bufferSize;
}

void FileAppender::closeWriter() {
    if (ofs != NULL) {
        apr_file_close(ofs);
        ofs = NULL;
    }
}

void FileAppender::setBufferedIO(bool bufferedIO)
{
        this->bufferedIO = bufferedIO;
        if(bufferedIO)
        {
                immediateFlush = false;
        }
}

void FileAppender::setOption(const LogString& option,
        const LogString& value)
{
        if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILE"), LOG4CXX_STR("file"))
                || StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILENAME"), LOG4CXX_STR("filename")))
        {
                fileName = value;
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("APPEND"), LOG4CXX_STR("append")))
        {
                fileAppend = OptionConverter::toBoolean(value, true);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFEREDIO"), LOG4CXX_STR("bufferedio")))
        {
                bufferedIO = OptionConverter::toBoolean(value, true);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("IMMEDIATEFLUSH"), LOG4CXX_STR("immediateflush")))
        {
                bufferedIO = !OptionConverter::toBoolean(value, false);
        }
        else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFERSIZE"), LOG4CXX_STR("buffersize")))
        {
                bufferSize = OptionConverter::toFileSize(value, 8*1024);
        }
        else
        {
                WriterAppender::setOption(option, value);
        }
}

void FileAppender::activateOptions(Pool& p)
{
        if (fileName.getName().empty()) {
          LogLog::warn((LogString) LOG4CXX_STR("File option not set for appender [")
              + name + LOG4CXX_STR("]."));
          LogLog::warn(LOG4CXX_STR("Are you using FileAppender instead of ConsoleAppender?"));
        } else {
          synchronized sync(mutex);
          if (ofs != NULL) {
            LogLog::warn((LogString) LOG4CXX_STR("Appender [") +
                 name + LOG4CXX_STR("] already open."));
          }
          apr_fileperms_t perm = APR_OS_DEFAULT;
          apr_int32_t flags = APR_WRITE | APR_CREATE;
          if (fileAppend) {
            flags |= APR_APPEND;
          } else {
            flags |= APR_TRUNCATE;
          }
          if (bufferedIO) {
            flags |= APR_BUFFERED;
          }
          ofs = NULL;
          fileName.open(&ofs, flags, perm, pool);
          fileClosed = 0;
        }
        if (ofs != NULL) {
          writeHeader(p);
        }
}

void FileAppender::subAppend(const char* encoded, log4cxx_size_t size, Pool& p) {
  if (ofs != NULL) {
    apr_file_write(ofs, encoded, &size);
    //
    //   do not call apr_file_flush here as it is a no-op
    //   on Unix and wildly expensive on Windows.
    //   See LOGCXX-58 for details
  }
}

<|endoftext|>


<commit_before><commit_msg>cppcheck: Redundant checking of STL container<commit_after><|endoftext|>


<commit_before>//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2012 Esteban Tovagliari.
//
// 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.
//

// Has to be first, to avoid redifinition warnings.
#include "bind_auto_release_ptr.h"

#include "renderer/utility/transformsequence.h"
#include "foundation/utility/iostreamop.h"

namespace bpy = boost::python;
using namespace foundation;
using namespace renderer;

namespace detail
{

template<class T>
void bind_typed_transform( const char *class_name)
{
    typedef typename Transform<T>::MatrixType MatrixType;

    bpy::class_<Transform<T> >( class_name)
        .def( bpy::init<const MatrixType&>())
        .def( bpy::init<const MatrixType&, const MatrixType&>())

        .def( "identity", &Transform<T>::identity).staticmethod( "identity")

        .def( "get_local_to_parent", &Transform<T>::get_local_to_parent, bpy::return_value_policy<bpy::copy_const_reference>())
        .def( "get_parent_to_local", &Transform<T>::get_parent_to_local, bpy::return_value_policy<bpy::copy_const_reference>())

        .def( bpy::self * bpy::self)

		// a bug in boost::python, this needs
		// the extra self_ns qualification
		.def( bpy::self_ns::str( bpy::self))
		.def( bpy::self_ns::repr( bpy::self))
        ;
}

bpy::tuple transform_seq_get_transform( const TransformSequence& seq, std::size_t index)
{
    double time;
    Transformd xform;
    seq.get_transform( index, time, xform);
    return bpy::make_tuple( time, xform);
}

Transformd transform_seq_get_earliest( const TransformSequence& seq)
{
    return seq.earliest_transform();
}

} // detail

void bind_transform()
{
    detail::bind_typed_transform<float>( "Transformf");
    detail::bind_typed_transform<double>( "Transformd");

    bpy::class_<TransformSequence, boost::noncopyable>( "TransformSequence", bpy::no_init)
        .def( "clear", &TransformSequence::clear)
        .def( "set_transform", &TransformSequence::set_transform)
        .def( "get_transform", &detail::transform_seq_get_transform)
        .def( "earliest_transform", &detail::transform_seq_get_earliest)
        .def( "empty", &TransformSequence::empty)
        .def( "size", &TransformSequence::size)
        .def( "prepare", &TransformSequence::prepare)
        .def( "evaluate", &TransformSequence::evaluate)
        ;
}
<commit_msg>fixed mixed tabs/spaces.<commit_after>//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2012 Esteban Tovagliari.
//
// 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.
//

// Has to be first, to avoid redifinition warnings.
#include "bind_auto_release_ptr.h"

#include "renderer/utility/transformsequence.h"
#include "foundation/utility/iostreamop.h"

namespace bpy = boost::python;
using namespace foundation;
using namespace renderer;

namespace detail
{

template<class T>
void bind_typed_transform( const char *class_name)
{
    typedef typename Transform<T>::MatrixType MatrixType;

    bpy::class_<Transform<T> >( class_name)
        .def( bpy::init<const MatrixType&>())
        .def( bpy::init<const MatrixType&, const MatrixType&>())

        .def( "identity", &Transform<T>::identity).staticmethod( "identity")

        .def( "get_local_to_parent", &Transform<T>::get_local_to_parent, bpy::return_value_policy<bpy::copy_const_reference>())
        .def( "get_parent_to_local", &Transform<T>::get_parent_to_local, bpy::return_value_policy<bpy::copy_const_reference>())

        .def( bpy::self * bpy::self)

        // a bug in boost::python, this needs
        // the extra self_ns qualification
        .def( bpy::self_ns::str( bpy::self))
        .def( bpy::self_ns::repr( bpy::self))
        ;
}

bpy::tuple transform_seq_get_transform( const TransformSequence& seq, std::size_t index)
{
    double time;
    Transformd xform;
    seq.get_transform( index, time, xform);
    return bpy::make_tuple( time, xform);
}

Transformd transform_seq_get_earliest( const TransformSequence& seq)
{
    return seq.earliest_transform();
}

} // detail

void bind_transform()
{
    detail::bind_typed_transform<float>( "Transformf");
    detail::bind_typed_transform<double>( "Transformd");

    bpy::class_<TransformSequence, boost::noncopyable>( "TransformSequence", bpy::no_init)
        .def( "clear", &TransformSequence::clear)
        .def( "set_transform", &TransformSequence::set_transform)
        .def( "get_transform", &detail::transform_seq_get_transform)
        .def( "earliest_transform", &detail::transform_seq_get_earliest)
        .def( "empty", &TransformSequence::empty)
        .def( "size", &TransformSequence::size)
        .def( "prepare", &TransformSequence::prepare)
        .def( "evaluate", &TransformSequence::evaluate)
        ;
}
<|endoftext|>