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

#ifndef __BENG_HTTP_SERVER_INTERNAL_H
#define __BENG_HTTP_SERVER_INTERNAL_H

#include "Error.hxx"
#include "http_server.hxx"
#include "http_body.hxx"
#include "filtered_socket.hxx"
#include "net/SocketAddress.hxx"
#include "event/TimerEvent.hxx"
#include "event/DeferEvent.hxx"
#include "istream/Pointer.hxx"
#include "http/Method.h"
#include "util/Cancellable.hxx"
#include "util/Exception.hxx"

struct HttpServerConnection final : IstreamHandler {
    enum class BucketResult {
        MORE,
        BLOCKING,
        DEPLETED,
        DESTROYED,
    };

    struct RequestBodyReader : HttpBodyReader {
        HttpServerConnection &connection;

        RequestBodyReader(struct pool &_pool,
                          HttpServerConnection &_connection)
            :HttpBodyReader(_pool),
             connection(_connection) {}

        /* virtual methods from class Istream */

        off_t _GetAvailable(bool partial) override;
        void _Read() override;
        void _Close() override;
    };

    struct pool *pool;

    /* I/O */
    FilteredSocket socket;

    /**
     * Track the total time for idle periods plus receiving all
     * headers from the client.  Unlike the #filtered_socket read
     * timeout, it is not refreshed after receiving some header data.
     */
    TimerEvent idle_timeout;

    DeferEvent defer_read;

    enum http_server_score score = HTTP_SERVER_NEW;

    /* handler */
    HttpServerConnectionHandler *handler;

    /* info */

    SocketAddress local_address, remote_address;

    const char *local_host_and_port;
    const char *remote_host_and_port, *remote_host;

    /* request */
    struct Request {
        enum {
            /** there is no request (yet); waiting for the request
                line */
            START,

            /** parsing request headers; waiting for empty line */
            HEADERS,

            /** reading the request body */
            BODY,

            /** the request has been consumed, and we are going to send the response */
            END
        } read_state = START;

        /**
         * This flag is true if we are currently calling the HTTP
         * request handler.  During this period,
         * http_server_request_stream_read() does nothing, to prevent
         * recursion.
         */
        bool in_handler;

        /** has the client sent a HTTP/1.0 request? */
        bool http_1_0;

        /** did the client send an "Expect: 100-continue" header? */
        bool expect_100_continue;

        /** send a "417 Expectation Failed" response? */
        bool expect_failed;

        HttpServerRequest *request = nullptr;

        CancellablePointer cancel_ptr;

        uint64_t bytes_received = 0;
    } request;

    /** the request body reader; this variable is only valid if
        read_state==READ_BODY */
    RequestBodyReader *request_body_reader;

    /** the response; this struct is only valid if
        read_state==READ_BODY||read_state==READ_END */
    struct Response {
        bool want_write;

        /**
         * Are we currently waiting for all output buffers to be
         * drained, before we can close the socket?
         *
         * @see BufferedSocketHandler::drained
         * @see http_server_socket_drained()
         */
        bool pending_drained = false;

        http_status_t status;
        char status_buffer[64];
        char content_length_buffer[32];
        IstreamPointer istream;
        off_t length;

        uint64_t bytes_sent = 0;

        Response()
            :istream(nullptr) {}
    } response;

    bool date_header;

    /* connection settings */
    bool keep_alive;

    HttpServerConnection(struct pool &_pool,
                         EventLoop &_loop,
                         SocketDescriptor fd, FdType fd_type,
                         const SocketFilter *filter,
                         void *filter_ctx,
                         SocketAddress _local_address,
                         SocketAddress _remote_address,
                         bool _date_header,
                         HttpServerConnectionHandler &_handler);

    ~HttpServerConnection() {
        defer_read.Cancel();
    }

    void Delete() {
        this->~HttpServerConnection();
        pool_unref(pool);
    }

    EventLoop &GetEventLoop() {
        return defer_read.GetEventLoop();
    }

    gcc_pure
    bool IsValid() const {
        return socket.IsValid() && socket.IsConnected();
    }

    void IdleTimeoutCallback();

    void Log();

    void OnDeferredRead();

    /**
     * @return false if the connection has been closed
     */
    bool ParseRequestLine(const char *line, size_t length);

    /**
     * @return false if the connection has been closed
     */
    bool HeadersFinished();

    /**
     * @return false if the connection has been closed
     */
    bool HandleLine(const char *line, size_t length);

    BufferedResult FeedHeaders(const void *_data, size_t length);

    /**
     * @return false if the connection has been closed
     */
    bool SubmitRequest();

    /**
     * @return false if the connection has been closed
     */
    BufferedResult Feed(const void *data, size_t size);

    /**
     * Send data from the input buffer to the request body istream
     * handler.
     */
    BufferedResult FeedRequestBody(const void *data, size_t size);

    /**
     * Attempt a "direct" transfer of the request body.  Caller must
     * hold an additional pool reference.
     */
    DirectResult TryRequestBodyDirect(int fd, FdType fd_type);

    /**
     * @return false if the connection has been closed
     */
    bool MaybeSend100Continue();

    void SetResponseIstream(Istream &r);

    /**
     * To be called after the response istream has seen end-of-file,
     * and has been destroyed.
     *
     * @return false if the connection has been closed
     */
    bool ResponseIstreamFinished();

    void SubmitResponse(http_status_t status,
                        HttpHeaders &&headers,
                        Istream *body);

    void ScheduleWrite() {
        response.want_write = true;
        socket.ScheduleWrite();
    }

    /**
     * @return false if the connection has been closed
     */
    bool TryWrite();
    BucketResult TryWriteBuckets2();
    BucketResult TryWriteBuckets();

    void CloseRequest();

    void CloseSocket();
    void DestroySocket();

    /**
     * The last response on this connection is finished, and it should
     * be closed.
     */
    void Done();

    /**
     * The peer has closed the socket.
     */
    void Cancel();

    /**
     * A fatal error has occurred, and the connection should be closed
     * immediately, without sending any further information to the
     * client.  This invokes
     * HttpServerConnectionHandler::HttpConnectionError(), but not
     * HttpServerConnectionHandler::HttpConnectionClosed().
     */
    void Error(std::exception_ptr e);

    void Error(const char *msg);

    void SocketErrorErrno(const char *msg);

    template<typename T>
    void SocketError(T &&t) {
        try {
            ThrowException(std::forward<T>(t));
        } catch (...) {
            Error(std::make_exception_ptr(HttpServerSocketError()));
        }
    }

    void SocketError(const char *msg) {
        SocketError(std::runtime_error(msg));
    }

    void ProtocolError(const char *msg) {
        Error(std::make_exception_ptr(HttpServerProtocolError(msg)));
    }

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) override;
    void OnEof() override;
    void OnError(std::exception_ptr ep) override;
};

/**
 * The timeout of an idle connection (READ_START).
 */
extern const struct timeval http_server_idle_timeout;

/**
 * The total timeout of a client sending request headers.
 */
extern const struct timeval http_server_header_timeout;

/**
 * The timeout for reading more request data (READ_BODY).
 */
extern const struct timeval http_server_read_timeout;

/**
 * The timeout for writing more response data (READ_BODY, READ_END).
 */
extern const struct timeval http_server_write_timeout;

HttpServerRequest *
http_server_request_new(HttpServerConnection *connection,
                        http_method_t method,
                        StringView uri);

#endif
<commit_msg>http_server: make several attributes const<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __BENG_HTTP_SERVER_INTERNAL_H
#define __BENG_HTTP_SERVER_INTERNAL_H

#include "Error.hxx"
#include "http_server.hxx"
#include "http_body.hxx"
#include "filtered_socket.hxx"
#include "net/SocketAddress.hxx"
#include "event/TimerEvent.hxx"
#include "event/DeferEvent.hxx"
#include "istream/Pointer.hxx"
#include "http/Method.h"
#include "util/Cancellable.hxx"
#include "util/Exception.hxx"

struct HttpServerConnection final : IstreamHandler {
    enum class BucketResult {
        MORE,
        BLOCKING,
        DEPLETED,
        DESTROYED,
    };

    struct RequestBodyReader : HttpBodyReader {
        HttpServerConnection &connection;

        RequestBodyReader(struct pool &_pool,
                          HttpServerConnection &_connection)
            :HttpBodyReader(_pool),
             connection(_connection) {}

        /* virtual methods from class Istream */

        off_t _GetAvailable(bool partial) override;
        void _Read() override;
        void _Close() override;
    };

    struct pool *const pool;

    /* I/O */
    FilteredSocket socket;

    /**
     * Track the total time for idle periods plus receiving all
     * headers from the client.  Unlike the #filtered_socket read
     * timeout, it is not refreshed after receiving some header data.
     */
    TimerEvent idle_timeout;

    DeferEvent defer_read;

    enum http_server_score score = HTTP_SERVER_NEW;

    /* handler */
    HttpServerConnectionHandler *handler;

    /* info */

    const SocketAddress local_address, remote_address;

    const char *const local_host_and_port;
    const char *const remote_host_and_port, *const remote_host;

    /* request */
    struct Request {
        enum {
            /** there is no request (yet); waiting for the request
                line */
            START,

            /** parsing request headers; waiting for empty line */
            HEADERS,

            /** reading the request body */
            BODY,

            /** the request has been consumed, and we are going to send the response */
            END
        } read_state = START;

        /**
         * This flag is true if we are currently calling the HTTP
         * request handler.  During this period,
         * http_server_request_stream_read() does nothing, to prevent
         * recursion.
         */
        bool in_handler;

        /** has the client sent a HTTP/1.0 request? */
        bool http_1_0;

        /** did the client send an "Expect: 100-continue" header? */
        bool expect_100_continue;

        /** send a "417 Expectation Failed" response? */
        bool expect_failed;

        HttpServerRequest *request = nullptr;

        CancellablePointer cancel_ptr;

        uint64_t bytes_received = 0;
    } request;

    /** the request body reader; this variable is only valid if
        read_state==READ_BODY */
    RequestBodyReader *request_body_reader;

    /** the response; this struct is only valid if
        read_state==READ_BODY||read_state==READ_END */
    struct Response {
        bool want_write;

        /**
         * Are we currently waiting for all output buffers to be
         * drained, before we can close the socket?
         *
         * @see BufferedSocketHandler::drained
         * @see http_server_socket_drained()
         */
        bool pending_drained = false;

        http_status_t status;
        char status_buffer[64];
        char content_length_buffer[32];
        IstreamPointer istream;
        off_t length;

        uint64_t bytes_sent = 0;

        Response()
            :istream(nullptr) {}
    } response;

    bool date_header;

    /* connection settings */
    bool keep_alive;

    HttpServerConnection(struct pool &_pool,
                         EventLoop &_loop,
                         SocketDescriptor fd, FdType fd_type,
                         const SocketFilter *filter,
                         void *filter_ctx,
                         SocketAddress _local_address,
                         SocketAddress _remote_address,
                         bool _date_header,
                         HttpServerConnectionHandler &_handler);

    ~HttpServerConnection() {
        defer_read.Cancel();
    }

    void Delete() {
        this->~HttpServerConnection();
        pool_unref(pool);
    }

    EventLoop &GetEventLoop() {
        return defer_read.GetEventLoop();
    }

    gcc_pure
    bool IsValid() const {
        return socket.IsValid() && socket.IsConnected();
    }

    void IdleTimeoutCallback();

    void Log();

    void OnDeferredRead();

    /**
     * @return false if the connection has been closed
     */
    bool ParseRequestLine(const char *line, size_t length);

    /**
     * @return false if the connection has been closed
     */
    bool HeadersFinished();

    /**
     * @return false if the connection has been closed
     */
    bool HandleLine(const char *line, size_t length);

    BufferedResult FeedHeaders(const void *_data, size_t length);

    /**
     * @return false if the connection has been closed
     */
    bool SubmitRequest();

    /**
     * @return false if the connection has been closed
     */
    BufferedResult Feed(const void *data, size_t size);

    /**
     * Send data from the input buffer to the request body istream
     * handler.
     */
    BufferedResult FeedRequestBody(const void *data, size_t size);

    /**
     * Attempt a "direct" transfer of the request body.  Caller must
     * hold an additional pool reference.
     */
    DirectResult TryRequestBodyDirect(int fd, FdType fd_type);

    /**
     * @return false if the connection has been closed
     */
    bool MaybeSend100Continue();

    void SetResponseIstream(Istream &r);

    /**
     * To be called after the response istream has seen end-of-file,
     * and has been destroyed.
     *
     * @return false if the connection has been closed
     */
    bool ResponseIstreamFinished();

    void SubmitResponse(http_status_t status,
                        HttpHeaders &&headers,
                        Istream *body);

    void ScheduleWrite() {
        response.want_write = true;
        socket.ScheduleWrite();
    }

    /**
     * @return false if the connection has been closed
     */
    bool TryWrite();
    BucketResult TryWriteBuckets2();
    BucketResult TryWriteBuckets();

    void CloseRequest();

    void CloseSocket();
    void DestroySocket();

    /**
     * The last response on this connection is finished, and it should
     * be closed.
     */
    void Done();

    /**
     * The peer has closed the socket.
     */
    void Cancel();

    /**
     * A fatal error has occurred, and the connection should be closed
     * immediately, without sending any further information to the
     * client.  This invokes
     * HttpServerConnectionHandler::HttpConnectionError(), but not
     * HttpServerConnectionHandler::HttpConnectionClosed().
     */
    void Error(std::exception_ptr e);

    void Error(const char *msg);

    void SocketErrorErrno(const char *msg);

    template<typename T>
    void SocketError(T &&t) {
        try {
            ThrowException(std::forward<T>(t));
        } catch (...) {
            Error(std::make_exception_ptr(HttpServerSocketError()));
        }
    }

    void SocketError(const char *msg) {
        SocketError(std::runtime_error(msg));
    }

    void ProtocolError(const char *msg) {
        Error(std::make_exception_ptr(HttpServerProtocolError(msg)));
    }

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) override;
    void OnEof() override;
    void OnError(std::exception_ptr ep) override;
};

/**
 * The timeout of an idle connection (READ_START).
 */
extern const struct timeval http_server_idle_timeout;

/**
 * The total timeout of a client sending request headers.
 */
extern const struct timeval http_server_header_timeout;

/**
 * The timeout for reading more request data (READ_BODY).
 */
extern const struct timeval http_server_read_timeout;

/**
 * The timeout for writing more response data (READ_BODY, READ_END).
 */
extern const struct timeval http_server_write_timeout;

HttpServerRequest *
http_server_request_new(HttpServerConnection *connection,
                        http_method_t method,
                        StringView uri);

#endif
<|endoftext|>


<commit_before>
#include <sstream>
#include <algorithm>

#include "http_v1_request_head.hpp"

namespace manifold
{
  namespace http
  {
    //----------------------------------------------------------------//
    static const std::string empty_string;
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const request_head& generic_head)
    {
      this->headers_ = generic_head.raw_headers();
      this->authority(generic_head.authority());
      this->method(generic_head.method());
      this->path(generic_head.path());
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const std::string& path, const std::string& method, std::list<std::pair<std::string,std::string>>&& headers)
    {
      this->headers_ = std::move(headers);
      this->path(path);
      this->method(method);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const std::string& path, http::method method, std::list<std::pair<std::string,std::string>>&& headers)
    {
      this->headers_ = std::move(headers);
      this->path(path);
      this->method(method);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::~v1_request_head()
    {
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::method() const
    {
      return this->method_;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::method(const std::string& value)
    {
      this->method_ = value;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::method(http::method value)
    {
      this->method(method_enum_to_string(value));
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::path() const
    {

      return this->path_;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::path(const std::string& value)
    {
      this->path_ = value;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::scheme() const
    {
      return empty_string;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::scheme(const std::string& value)
    {

    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::authority() const
    {
      return this->header("host");
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::authority(const std::string& value)
    {
      this->header("host", value);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    bool v1_request_head::start_line(std::string&& value)
    {
      bool ret = false;

      std::size_t first_space = value.find(' ');
      std::size_t last_space = value.rfind(' ');
      if (first_space != std::string::npos && last_space != std::string::npos)
      {
        this->method_ = value.substr(0, first_space);
        ++first_space;
        this->path_ = value.substr(first_space, last_space - first_space);
        ret = true;
      }

      return ret;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    std::string v1_request_head::start_line() const
    {
      std::string ret(this->method_ + " " + this->path_ + " http/1.1");
      return ret;
    }
    //----------------------------------------------------------------//
  }
}<commit_msg>Fixed lower case http version in request line.<commit_after>
#include <sstream>
#include <algorithm>

#include "http_v1_request_head.hpp"

namespace manifold
{
  namespace http
  {
    //----------------------------------------------------------------//
    static const std::string empty_string;
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const request_head& generic_head)
    {
      this->headers_ = generic_head.raw_headers();
      this->authority(generic_head.authority());
      this->method(generic_head.method());
      this->path(generic_head.path());
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const std::string& path, const std::string& method, std::list<std::pair<std::string,std::string>>&& headers)
    {
      this->headers_ = std::move(headers);
      this->path(path);
      this->method(method);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::v1_request_head(const std::string& path, http::method method, std::list<std::pair<std::string,std::string>>&& headers)
    {
      this->headers_ = std::move(headers);
      this->path(path);
      this->method(method);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    v1_request_head::~v1_request_head()
    {
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::method() const
    {
      return this->method_;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::method(const std::string& value)
    {
      this->method_ = value;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::method(http::method value)
    {
      this->method(method_enum_to_string(value));
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::path() const
    {

      return this->path_;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::path(const std::string& value)
    {
      this->path_ = value;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::scheme() const
    {
      return empty_string;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::scheme(const std::string& value)
    {

    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    const std::string& v1_request_head::authority() const
    {
      return this->header("host");
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    void v1_request_head::authority(const std::string& value)
    {
      this->header("host", value);
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    bool v1_request_head::start_line(std::string&& value)
    {
      bool ret = false;

      std::size_t first_space = value.find(' ');
      std::size_t last_space = value.rfind(' ');
      if (first_space != std::string::npos && last_space != std::string::npos)
      {
        this->method_ = value.substr(0, first_space);
        ++first_space;
        this->path_ = value.substr(first_space, last_space - first_space);
        ret = true;
      }

      return ret;
    }
    //----------------------------------------------------------------//

    //----------------------------------------------------------------//
    std::string v1_request_head::start_line() const
    {
      std::string ret(this->method_ + " " + this->path_ + " HTTP/1.1");
      return ret;
    }
    //----------------------------------------------------------------//
  }
}<|endoftext|>


<commit_before>#include "uniforms.h"

#include <Tempest/UniformBuffer>

using namespace Tempest;

Uniforms::Uniforms(Device &dev, AbstractGraphicsApi::Desc *desc)
  :dev(&dev),desc(desc) {
  }

Uniforms::Uniforms(Uniforms && u)
  :dev(u.dev), desc(std::move(u.desc)) {
  }

Uniforms::~Uniforms() {
  if(dev)
    dev->destroy(*this);
  }

Uniforms& Uniforms::operator=(Uniforms &&u) {
  dev =u.dev;
  desc=std::move(u.desc);
  return *this;
  }

void Uniforms::set(size_t layoutBind, const UniformBuffer &vbuf) {
  set(layoutBind,vbuf,0,vbuf.size());
  }

void Uniforms::set(size_t layoutBind, const Texture2d &tex) {
  if(tex.impl.handler)
    desc.handler->set(layoutBind,tex.impl.handler);
  }

void Uniforms::set(size_t layoutBind, const Detail::ResourcePtr<Texture2d> &tex) {
  if(tex.impl.handler)
    desc.handler->set(layoutBind,tex.impl.handler);
  }

void Uniforms::set(size_t layoutBind, const UniformBuffer &vbuf, size_t offset, size_t size) {
  if(vbuf.impl.impl.handler)
    desc.handler->set(layoutBind,vbuf.impl.impl.handler,offset,size); else
    throw std::logic_error("invalid uniform buffer");
  }
<commit_msg>throw for bad textures in ubo<commit_after>#include "uniforms.h"

#include <Tempest/UniformBuffer>

using namespace Tempest;

Uniforms::Uniforms(Device &dev, AbstractGraphicsApi::Desc *desc)
  :dev(&dev),desc(desc) {
  }

Uniforms::Uniforms(Uniforms && u)
  :dev(u.dev), desc(std::move(u.desc)) {
  }

Uniforms::~Uniforms() {
  if(dev)
    dev->destroy(*this);
  }

Uniforms& Uniforms::operator=(Uniforms &&u) {
  dev =u.dev;
  desc=std::move(u.desc);
  return *this;
  }

void Uniforms::set(size_t layoutBind, const UniformBuffer &vbuf) {
  set(layoutBind,vbuf,0,vbuf.size());
  }

void Uniforms::set(size_t layoutBind, const Texture2d &tex) {
  if(tex.impl.handler)
    desc.handler->set(layoutBind,tex.impl.handler); else
    throw std::logic_error("invalid texture");
  }

void Uniforms::set(size_t layoutBind, const Detail::ResourcePtr<Texture2d> &tex) {
  if(tex.impl.handler)
    desc.handler->set(layoutBind,tex.impl.handler);
  }

void Uniforms::set(size_t layoutBind, const UniformBuffer &vbuf, size_t offset, size_t size) {
  if(vbuf.impl.impl.handler)
    desc.handler->set(layoutBind,vbuf.impl.impl.handler,offset,size); else
    throw std::logic_error("invalid uniform buffer");
  }
<|endoftext|>


<commit_before>#include "stdafx.h"

const static InputElement elements[] =
{
	AF_INPUT_ELEMENT(0, "POSITION", AFF_R32G32B32_FLOAT, 0),
	AF_INPUT_ELEMENT(1, "COLOR", AFF_R32G32B32_FLOAT, 12),
};

struct Vertex
{
	Vec3 pos;
	Vec3 color;
};

class Picking
{
	AFRenderStates polygonRenderStates;
	AFRenderStates lineRenderStates;
public:
	Picking();
	void Update2D(Vertex v[3]);
	void Update3D(Vertex poly[3], Vertex lines[6]);
	void Draw2D();
	void Draw3D();
};

#define CLASSNAME "Picking"
#define GET_PICKING \
	Picking* p = (Picking*)luaL_checkudata(L, 1, CLASSNAME);	\
	if (!p) {	\
		return 0;	\
	}

class PickingBinder {
public:
	PickingBinder() {
		GetLuaBindFuncContainer().push_back([](lua_State* L) {
			static luaL_Reg methods[] =
			{
				{ "Draw2D", [](lua_State* L) { GET_PICKING p->Draw2D(); return 0; } },
				{ "Draw3D", [](lua_State* L) { GET_PICKING p->Draw3D(); return 0; } },
				{ "__gc", [](lua_State* L) { GET_PICKING p->~Picking(); return 0; } },
				{ nullptr, nullptr },
			};
			aflBindClass(L, CLASSNAME, methods, [](lua_State* L) { void* u = lua_newuserdata(L, sizeof(Picking)); new (u) Picking(); return 1; });
		});
	}
} static binder;

Picking::Picking()
{
	polygonRenderStates.Create("solid", arrayparam(elements), AFRS_DEPTH_ENABLE);
	lineRenderStates.Create("solid", arrayparam(elements), AFRS_DEPTH_ENABLE | AFRS_PRIMITIVE_LINELIST);
}

void ScreenPosToRay(const Vec2& scrPos, Vec3& nearPos, Vec3& farPos)
{
	Mat v, p;
	matrixMan.Get(MatrixMan::VIEW, v);
	matrixMan.Get(MatrixMan::PROJ, p);
	Mat vp = makeViewportMatrix(systemMisc.GetScreenSize());
	Mat mInv = inv(v * p * vp);
	Vec4 nearPos4 = transform(Vec4(scrPos.x, scrPos.y, NDC_SPACE_NEAR, 1), mInv);
	Vec4 farPos4 = transform(Vec4(scrPos.x, scrPos.y, NDC_SPACE_FAR, 1), mInv);
	nearPos = Vec3(nearPos4.x, nearPos4.y, nearPos4.z) / nearPos4.w;
	farPos = Vec3(farPos4.x, farPos4.y, farPos4.z) / farPos4.w;
}

bool RayVsTriangle(const Vec3& ray1, const Vec3& ray2, const Vec3 triangle[])
{
	Vec3 rayDir = ray2 - ray1;
	float inner[3];
	for (int i = 0; i < 3; i++) {
		const Vec3& a = triangle[i];
		const Vec3& b = triangle[(i + 1) % 3];
		inner[i] = dot(cross(ray1 - a, a - b), rayDir);
	}
	return (inner[0] < 0 && inner[1] < 0 && inner[2] < 0) || (inner[0] > 0 && inner[1] > 0 && inner[2] > 0);
}

bool RayVsTriangleMollerTrumbore(const Vec3& ray1, const Vec3& ray2, const Vec3 triangle[], Vec3& hitPos)
{
	Vec3 ray1relative = ray1 - triangle[0];
	Vec3 axes[] = { triangle[1] - triangle[0], triangle[2] - triangle[0], ray1 - ray2 };
	Vec3 crosses[] = { cross(axes[1], axes[2]), cross(axes[2], axes[0]), cross(axes[0], axes[1]) };
	Vec3 uvt = Vec3(dot(ray1relative, crosses[0]), dot(ray1relative, crosses[1]), dot(ray1relative, crosses[2])) / std::max(dot(axes[0], crosses[0]), 0.000001f);
	hitPos = lerp(ray1, ray2, uvt.z);
	return uvt.x >= 0 && uvt.y >= 0 && (uvt.x + uvt.y) <= 1.f;
}

void Picking::Update2D(Vertex v[3])
{
	float radian = (float)(std::fmod(GetTime(), 3) * M_PI * 2 / 3);
	float radius = 0.5f;
	float aspect = (float)systemMisc.GetScreenSize().x / systemMisc.GetScreenSize().y;
	for (int i = 0; i < 3; i++) {
		static Vec3 center(-0.7f, 0.7f, 0.f);
		radian += (float)M_PI * 2 / 3;
		v[i].pos = Vec3(std::sin(radian) / aspect, std::cos(radian), 0) * radius + center;
	}

	bool hit = true;

	Vec2 scrPos = systemMisc.GetScreenSize();
	Vec2 curPos = systemMisc.GetMousePos();

	Vec2 curPosIn2D = curPos / scrPos * Vec2(2, -2) + Vec2(-1, 1);

	Mat proj2d;
#ifdef AF_VULKAN
	proj2d._22 = -1;
#endif
	Mat projVp = proj2d * makeViewportMatrix(scrPos);
	Vec3 transformed = transform(Vec3(curPos.x, curPos.y, 1), inv(projVp));
	assert(std::abs(transformed.x - curPosIn2D.x) < 0.001f);
	assert(std::abs(transformed.y - curPosIn2D.y) < 0.001f);

	for (int i = 0; i < 3; i++) {
		Vec3 dir = v[(i + 1) % 3].pos - v[i].pos;
		Vec3 cursorDir = Vec3(curPosIn2D.x, curPosIn2D.y, 0) - v[i].pos;
		if (cross(dir, cursorDir).z > 0) {
			hit = false;
		}
	}

	for (int i = 0; i < 3; i++) {
		v[i].color = hit ? Vec3(i == 0, i == 1, i == 2) : Vec3(0.5, 0.5, 0.5);
	}
}

void Picking::Update3D(Vertex poly[3], Vertex lines[6])
{
	float radian = (float)(std::fmod(GetTime(), 10) * M_PI * 2 / 10);
	float radius = 50.f;
	Vec3 triangle[3];
	for (int i = 0; i < 3; i++) {
		radian += (float)M_PI * 2 / 3;
		triangle[i] = poly[i].pos = Vec3(std::sin(radian) * radius, std::cos(radian) * radius, 50.f);
		poly[i].color = Vec3(0.5, 0.5, 0.5);
	}

	Vec3 n, f;
	ScreenPosToRay(systemMisc.GetMousePos(), n, f);
	Vec3 hitPos;
	bool hit = RayVsTriangleMollerTrumbore(n, f, triangle, hitPos);
	for (int i = 0; i < 3; i++)
	{
		poly[i].color = hit ? Vec3(i == 0, i == 1, i == 2) : Vec3(0.5, 0.5, 0.5);
	}

	for (int i = 0; i < 3; i++)
	{
		Vec3 axis = Vec3(i == 0, i == 1, i == 2);
		lines[i * 2].color = lines[i * 2 + 1].color = axis;
		lines[i * 2].pos = hitPos + axis * 10;
		lines[i * 2 + 1].pos = hitPos + axis * -10;
	}
}

void Picking::Draw3D()
{
	Vertex poly[3], lines[6];
	Update3D(poly, lines);
	Mat mView, mProj;
	matrixMan.Get(MatrixMan::VIEW, mView);
	matrixMan.Get(MatrixMan::PROJ, mProj);
	Mat mVP = mView * mProj;

	AFCommandList& cmd = afGetCommandList();
	cmd.SetRenderStates(polygonRenderStates);
	cmd.SetVertexBuffer(sizeof(poly), poly, sizeof(Vertex));
	cmd.SetBuffer(sizeof(Mat), &mVP, 0);
	cmd.Draw(3);

	cmd.SetRenderStates(lineRenderStates);
	cmd.SetVertexBuffer(sizeof(lines), lines, sizeof(Vertex));
	cmd.SetBuffer(sizeof(Mat), &mVP, 0);
	cmd.Draw(6);
}

void Picking::Draw2D()
{
	AFCommandList& cmd = afGetCommandList();
	cmd.SetRenderStates(polygonRenderStates);
	Vertex v[3];
	Update2D(v);
	cmd.SetVertexBuffer(sizeof(v), v, sizeof(Vertex));
	Mat proj2d;
#ifdef AF_VULKAN
	proj2d._22 = -1;
#endif

	cmd.SetBuffer(sizeof(Mat), &proj2d, 0);
	cmd.Draw(3);
}
<commit_msg>[OpenGL] Fix compile error.<commit_after>#include "stdafx.h"

const static InputElement elements[] =
{
	AF_INPUT_ELEMENT(0, "POSITION", AFF_R32G32B32_FLOAT, 0),
	AF_INPUT_ELEMENT(1, "COLOR", AFF_R32G32B32_FLOAT, 12),
};

struct Vertex
{
	Vec3 pos;
	Vec3 color;
};

class Picking
{
	AFRenderStates polygonRenderStates;
	AFRenderStates lineRenderStates;
public:
	Picking();
	void Update2D(Vertex v[3]);
	void Update3D(Vertex poly[3], Vertex lines[6]);
	void Draw2D();
	void Draw3D();
};

#define CLASSNAME "Picking"
#define GET_PICKING \
	Picking* p = (Picking*)luaL_checkudata(L, 1, CLASSNAME);	\
	if (!p) {	\
		return 0;	\
	}

class PickingBinder {
public:
	PickingBinder() {
		GetLuaBindFuncContainer().push_back([](lua_State* L) {
			static luaL_Reg methods[] =
			{
				{ "Draw2D", [](lua_State* L) { GET_PICKING p->Draw2D(); return 0; } },
				{ "Draw3D", [](lua_State* L) { GET_PICKING p->Draw3D(); return 0; } },
				{ "__gc", [](lua_State* L) { GET_PICKING p->~Picking(); return 0; } },
				{ nullptr, nullptr },
			};
			aflBindClass(L, CLASSNAME, methods, [](lua_State* L) { void* u = lua_newuserdata(L, sizeof(Picking)); new (u) Picking(); return 1; });
		});
	}
} static binder;

Picking::Picking()
{
	polygonRenderStates.Create("solid", arrayparam(elements), AFRS_DEPTH_ENABLE);
	lineRenderStates.Create("solid", arrayparam(elements), AFRS_DEPTH_ENABLE | AFRS_PRIMITIVE_LINELIST);
}

void ScreenPosToRay(const Vec2& scrPos, Vec3& nearPos, Vec3& farPos)
{
	Mat v, p;
	matrixMan.Get(MatrixMan::VIEW, v);
	matrixMan.Get(MatrixMan::PROJ, p);
	Mat vp = makeViewportMatrix(systemMisc.GetScreenSize());
	Mat mInv = inv(v * p * vp);
	Vec4 nearPos4 = transform(Vec4(scrPos.x, scrPos.y, NDC_SPACE_NEAR, 1), mInv);
	Vec4 farPos4 = transform(Vec4(scrPos.x, scrPos.y, NDC_SPACE_FAR, 1), mInv);
	nearPos = Vec3(nearPos4.x, nearPos4.y, nearPos4.z) / nearPos4.w;
	farPos = Vec3(farPos4.x, farPos4.y, farPos4.z) / farPos4.w;
}

bool RayVsTriangle(const Vec3& ray1, const Vec3& ray2, const Vec3 triangle[])
{
	Vec3 rayDir = ray2 - ray1;
	float inner[3];
	for (int i = 0; i < 3; i++) {
		const Vec3& a = triangle[i];
		const Vec3& b = triangle[(i + 1) % 3];
		inner[i] = dot(cross(ray1 - a, a - b), rayDir);
	}
	return (inner[0] < 0 && inner[1] < 0 && inner[2] < 0) || (inner[0] > 0 && inner[1] > 0 && inner[2] > 0);
}

bool RayVsTriangleMollerTrumbore(const Vec3& ray1, const Vec3& ray2, const Vec3 triangle[], Vec3& hitPos)
{
	Vec3 ray1relative = ray1 - triangle[0];
	Vec3 axes[] = { triangle[1] - triangle[0], triangle[2] - triangle[0], ray1 - ray2 };
	Vec3 crosses[] = { cross(axes[1], axes[2]), cross(axes[2], axes[0]), cross(axes[0], axes[1]) };
	Vec3 uvt = Vec3(dot(ray1relative, crosses[0]), dot(ray1relative, crosses[1]), dot(ray1relative, crosses[2])) / std::max(dot(axes[0], crosses[0]), 0.000001f);
	hitPos = lerp(ray1, ray2, uvt.z);
	return uvt.x >= 0 && uvt.y >= 0 && (uvt.x + uvt.y) <= 1.f;
}

void Picking::Update2D(Vertex v[3])
{
	float radian = (float)(std::fmod(GetTime(), 3) * M_PI * 2 / 3);
	float radius = 0.5f;
	float aspect = (float)systemMisc.GetScreenSize().x / systemMisc.GetScreenSize().y;
	for (int i = 0; i < 3; i++) {
		static Vec3 center(-0.7f, 0.7f, 0.f);
		radian += (float)M_PI * 2 / 3;
		v[i].pos = Vec3(std::sin(radian) / aspect, std::cos(radian), 0) * radius + center;
	}

	bool hit = true;

	Vec2 scrPos = systemMisc.GetScreenSize();
	Vec2 curPos = systemMisc.GetMousePos();

	Vec2 curPosIn2D = curPos / scrPos * Vec2(2, -2) + Vec2(-1, 1);

	Mat proj2d;
#ifdef AF_VULKAN
	proj2d._22 = -1;
#endif
	Mat projVp = proj2d * makeViewportMatrix(scrPos);
	Vec3 transformed = transform(Vec3(curPos.x, curPos.y, 1), inv(projVp));
	assert(std::abs(transformed.x - curPosIn2D.x) < 0.001f);
	assert(std::abs(transformed.y - curPosIn2D.y) < 0.001f);

	for (int i = 0; i < 3; i++) {
		Vec3 dir = v[(i + 1) % 3].pos - v[i].pos;
		Vec3 cursorDir = Vec3(curPosIn2D.x, curPosIn2D.y, 0) - v[i].pos;
		if (cross(dir, cursorDir).z > 0) {
			hit = false;
		}
	}

	for (int i = 0; i < 3; i++) {
		v[i].color = hit ? Vec3(i == 0, i == 1, i == 2) : Vec3(0.5, 0.5, 0.5);
	}
}

void Picking::Update3D(Vertex poly[3], Vertex lines[6])
{
	float radian = (float)(std::fmod(GetTime(), 10) * M_PI * 2 / 10);
	float radius = 50.f;
	Vec3 triangle[3];
	for (int i = 0; i < 3; i++) {
		radian += (float)M_PI * 2 / 3;
		triangle[i] = poly[i].pos = Vec3(std::sin(radian) * radius, std::cos(radian) * radius, 50.f);
		poly[i].color = Vec3(0.5, 0.5, 0.5);
	}

	Vec3 n, f;
	ScreenPosToRay(systemMisc.GetMousePos(), n, f);
	Vec3 hitPos;
	bool hit = RayVsTriangleMollerTrumbore(n, f, triangle, hitPos);
	for (int i = 0; i < 3; i++)
	{
		poly[i].color = hit ? Vec3(i == 0, i == 1, i == 2) : Vec3(0.5, 0.5, 0.5);
	}

	for (int i = 0; i < 3; i++)
	{
		Vec3 axis = Vec3(i == 0, i == 1, i == 2);
		lines[i * 2].color = lines[i * 2 + 1].color = axis;
		lines[i * 2].pos = hitPos + axis * 10;
		lines[i * 2 + 1].pos = hitPos + axis * -10;
	}
}

static void DrawDynamicVertexBuffer(AFCommandList& cmd, int nVertices, Vertex vertices[])
{
#ifdef AF_GLES
	VBOID vbo = afCreateVertexBuffer(sizeof(Vertex) * nVertices, vertices);
	cmd.SetVertexBuffer(vbo, sizeof(Vertex));
	cmd.Draw(nVertices);
	afSafeDeleteBuffer(vbo);
#else
	cmd.SetVertexBuffer(sizeof(Vertex) * nVertices, vertices, sizeof(Vertex));
	cmd.Draw(nVertices);
#endif
}

void Picking::Draw3D()
{
	Vertex poly[3], lines[6];
	Update3D(poly, lines);
	Mat mView, mProj;
	matrixMan.Get(MatrixMan::VIEW, mView);
	matrixMan.Get(MatrixMan::PROJ, mProj);
	Mat mVP = mView * mProj;

	AFCommandList& cmd = afGetCommandList();
	cmd.SetRenderStates(polygonRenderStates);
	cmd.SetBuffer(sizeof(Mat), &mVP, 0);
	DrawDynamicVertexBuffer(cmd, arrayparam(poly));

	cmd.SetRenderStates(lineRenderStates);
	cmd.SetBuffer(sizeof(Mat), &mVP, 0);
	DrawDynamicVertexBuffer(cmd, arrayparam(lines));
}

void Picking::Draw2D()
{
	AFCommandList& cmd = afGetCommandList();
	cmd.SetRenderStates(polygonRenderStates);
	Vertex v[3];
	Update2D(v);
	Mat proj2d;
#ifdef AF_VULKAN
	proj2d._22 = -1;
#endif
	cmd.SetBuffer(sizeof(Mat), &proj2d, 0);
	DrawDynamicVertexBuffer(cmd, arrayparam(v));
}
<|endoftext|>


<commit_before>/*
 * Printipi
 * (c) 2014 Colin Wallace
 */

/*TODO:
 * *Write SN754410 drivers
 * *Test output on one single motor
 * *Figure out extrusion in State::queueMovement.
 * *in State::queueMovement, curX, curY, curZ, etc should be recalculated from the actual axis positions to prevent drift
 *    dest*Primitive must be maintained in order to handle relative movements.
 * *Add Kossel Axis drivers
 * *Run valgrind to hunt for uninitialized variables
 * *Enable new stepper driver
 * *Wire all three steppers
 *  Solder thermistor
 *  Add thermister support
 *  Add endstop support
 *  Add max/min bounds for each axis
 *  Add acceleration
 *  Make scheduler more resistant to skipping (make it so it can only run at up to, say, 2x speed to catch up. This minimizes missed steps)
 *  Investigate single-threading for entire process.
 *  Look into coordinate rounding for State::queueMovement
 *  Consider names: piprint (taken), printchef (exists), Rasprintian (play on raspbian), Rasprint, Rasprinti, Printipi
*/

#include <string>
#include <fcntl.h> //needed for (file) open()
//#include <stdlib.h> //needed for exit()
#include <sys/mman.h> //for mlockall
#include <cstdlib> //for atexit
#include "logging.h"

#include "gparse/serial.h"
#include "state.h"
#include "drivers/driver.h"
#include "drivers/kossel/kossel.h"
#include "argparse.h"

void printUsage(char* cmd) {
	//#ifndef NO_USAGE_INFO
	LOGE("usage: %s ttyFile\n", cmd);
    //std::cerr << "usage: " << cmd << " ttyFile" << std::endl;
    //#endif
    //exit(1);
}

/*void onExit() {
	LOG("Exiting\n");
}*/

int main(int argc, char** argv) {
	/*if (DO_LOG) {
		std::atexit(onExit);
	}*/
	if (argparse::cmdOptionExists(argv, argv+argc, "--quiet")) {
    	logging::disable();
    }
    if (argparse::cmdOptionExists(argv, argv+argc, "--verbose")) {
    	logging::enableVerbose();
    }
    if (argc < 2 || argparse::cmdOptionExists(argv, argv+argc, "-h") || argparse::cmdOptionExists(argv, argv+argc, "--help")) {
        printUsage(argv[0]);
        return 1;
    }

    //prevent page-swaps to increase performace:
    int retval = mlockall(MCL_FUTURE|MCL_CURRENT);
    if (retval) {
    	LOGW("Warning: mlockall (prevent memory swaps) in main.cpp::main() returned non-zero: %i\n", retval);
    }

    char* serialFileName = argv[1];
    LOG("Serial file: %s\n", serialFileName);
    int fd = open(serialFileName, O_RDWR);

    drv::Kossel driver;
	State<drv::Kossel> gState(driver);

    gparse::comLoop(fd, gState);
    return 0;
}
<commit_msg>Updated to-do<commit_after>/*
 * Printipi
 * (c) 2014 Colin Wallace
 */

/*TODO:
 * *Write SN754410 drivers
 * *Test output on one single motor
 * *Figure out extrusion in State::queueMovement.
 * *in State::queueMovement, curX, curY, curZ, etc should be recalculated from the actual axis positions to prevent drift
 *    dest*Primitive must be maintained in order to handle relative movements.
 * *Add Kossel Axis drivers
 * *Run valgrind to hunt for uninitialized variables
 * *Enable new stepper driver
 * *Wire all three steppers
 *  Solder thermistor
 *  Add thermister support
 *  Add endstop support
 *  Add max/min bounds for each axis
 *  Add acceleration
 *  Add IO deactivation upon exit
 *  Add ability to put steppers to rest upon idle
 *  Make scheduler more resistant to skipping (make it so it can only run at up to, say, 2x speed to catch up. This minimizes missed steps)
 *  Investigate single-threading for entire process.
 *  Look into coordinate rounding for State::queueMovement
 *  Consider names: piprint (taken), printchef (exists), Rasprintian (play on raspbian), Rasprint, Rasprinti, Printipi
*/

#include <string>
#include <fcntl.h> //needed for (file) open()
//#include <stdlib.h> //needed for exit()
#include <sys/mman.h> //for mlockall
//#include <cstdlib> //for atexit
#include "logging.h"

#include "gparse/serial.h"
#include "state.h"
#include "drivers/driver.h"
#include "drivers/kossel/kossel.h"
#include "argparse.h"

void printUsage(char* cmd) {
	//#ifndef NO_USAGE_INFO
	LOGE("usage: %s ttyFile\n", cmd);
    //std::cerr << "usage: " << cmd << " ttyFile" << std::endl;
    //#endif
    //exit(1);
}

/*void onExit() {
	LOG("Exiting\n");
}*/

int main(int argc, char** argv) {
	/*if (DO_LOG) {
		std::atexit(onExit);
	}*/
	if (argparse::cmdOptionExists(argv, argv+argc, "--quiet")) {
    	logging::disable();
    }
    if (argparse::cmdOptionExists(argv, argv+argc, "--verbose")) {
    	logging::enableVerbose();
    }
    if (argc < 2 || argparse::cmdOptionExists(argv, argv+argc, "-h") || argparse::cmdOptionExists(argv, argv+argc, "--help")) {
        printUsage(argv[0]);
        return 1;
    }

    //prevent page-swaps to increase performace:
    int retval = mlockall(MCL_FUTURE|MCL_CURRENT);
    if (retval) {
    	LOGW("Warning: mlockall (prevent memory swaps) in main.cpp::main() returned non-zero: %i\n", retval);
    }

    char* serialFileName = argv[1];
    LOG("Serial file: %s\n", serialFileName);
    int fd = open(serialFileName, O_RDWR);

    drv::Kossel driver;
	State<drv::Kossel> gState(driver);

    gparse::comLoop(fd, gState);
    return 0;
}
<|endoftext|>


<commit_before>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "LightningTree.h"

#include "../utils/linearAlg2D.h"

using namespace cura;

coord_t LightningTreeNode::getWeightedDistance(const Point& unsupported_loc, const coord_t& supporting_radius) const
{
    size_t valence = (!is_root) + children.size();
    coord_t boost = (0 < valence && valence < 4) ? 4 * supporting_radius : 0;
    return vSize(getLocation() - unsupported_loc) - boost;
}

bool LightningTreeNode::hasOffspring(const std::shared_ptr<LightningTreeNode>& to_be_checked) const
{
    if (to_be_checked == shared_from_this()) return true;
    for (auto child_ptr : children)
    {
        if (child_ptr->hasOffspring(to_be_checked)) return true;
    }
    return false;
}

const Point& LightningTreeNode::getLocation() const
{
    return p;
}

void LightningTreeNode::setLocation(const Point& loc)
{
    p = loc;
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::addChild(const Point& child_loc)
{
    assert(p != child_loc);
    children.push_back(LightningTreeNode::create(child_loc));
    return children.back();
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::addChild(std::shared_ptr<LightningTreeNode>& new_child)
{
    assert(new_child != shared_from_this());
    //     assert(p != new_child->p);
    if (p == new_child->p)
        std::cerr << "wtf\n";
    children.push_back(new_child);
    new_child->is_root = false;
    return new_child;
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::findClosestNode(const Point& x, const coord_t& supporting_radius)
{
    coord_t closest_distance = getWeightedDistance(x, supporting_radius);
    std::shared_ptr<LightningTreeNode> closest_node = shared_from_this();
    findClosestNodeHelper(x, supporting_radius, closest_distance, closest_node);
    return closest_node;
}

void LightningTreeNode::propagateToNextLayer
(
    std::vector<std::shared_ptr<LightningTreeNode>>& next_trees,
    const Polygons& next_outlines,
    const coord_t& prune_distance,
    const coord_t& smooth_magnitude
) const
{
    auto tree_below = deepCopy();

    // TODO: What is the correct order of the following operations?
    //       (NOTE: in case realign turns out _not_ to be last, would need to rewrite a few things, see the 'rerooted_parts' parameter of that function).
    tree_below->prune(prune_distance);
    tree_below->straighten(smooth_magnitude);
    if (tree_below->realign(next_outlines, next_trees))
    {
        next_trees.push_back(tree_below);
    }
}

// NOTE: Depth-first, as currently implemented.
//       Skips the root (because that has no root itself), but all initial nodes will have the root point anyway.
void LightningTreeNode::visitBranches(const branch_visitor_func_t& visitor) const
{
    for (const auto& node : children)
    {
        visitor(p, node->p);
        node->visitBranches(visitor);
    }
}

// NOTE: Depth-first, as currently implemented.
void LightningTreeNode::visitNodes(const node_visitor_func_t& visitor)
{
    visitor(shared_from_this());
    for (const auto& node : children)
    {
        node->visitNodes(visitor);
    }
}

// Node:
LightningTreeNode::LightningTreeNode(const Point& p) : is_root(false), p(p) {}

// Root (and Trunk):
LightningTreeNode::LightningTreeNode(const Point& a, const Point& b) : LightningTreeNode(a)
{
    children.push_back(LightningTreeNode::create(b));
    is_root = true;
}

void LightningTreeNode::findClosestNodeHelper(const Point& x, const coord_t supporting_radius, coord_t& closest_distance, std::shared_ptr<LightningTreeNode>& closest_node)
{
    for (const auto& node : children)
    {
        node->findClosestNodeHelper(x, supporting_radius, closest_distance, closest_node);
        const coord_t distance = node->getWeightedDistance(x, supporting_radius);
        if (distance < closest_distance)
        {
            closest_node = node;
            closest_distance = distance;
        }
    }
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::deepCopy() const
{
    std::shared_ptr<LightningTreeNode> local_root = LightningTreeNode::create(p);
    local_root->is_root = is_root;
    local_root->children.reserve(children.size());
    for (const auto& node : children)
    {
        local_root->children.push_back(node->deepCopy());
    }
    return local_root;
}

bool LightningTreeNode::realign(const Polygons& outlines, std::vector<std::shared_ptr<LightningTreeNode>>& rerooted_parts, const bool& connected_to_parent)
{
    // TODO: Hole(s) in the _middle_ of a line-segement, not unlikely since reconnect.
    // TODO: Reconnect if not on outline -> plan is: yes, but not here anymore!

    if (outlines.empty())
    {
        return false;
    }

    if (outlines.inside(p, true))
    {
        // Only keep children that have an unbroken connection to here, realign will put the rest in rerooted parts due to recursion:
        const std::function<bool(const std::shared_ptr<LightningTreeNode>& child)> remove_unconnected_func
        (
            [&outlines, &rerooted_parts](const std::shared_ptr<LightningTreeNode>& child)
            {
                constexpr bool argument_with_connected = true;
                return !child->realign(outlines, rerooted_parts, argument_with_connected);
            }
        );
        children.erase(std::remove_if(children.begin(), children.end(), remove_unconnected_func), children.end());
        return true;
    }

    // 'Lift' any decendants out of this tree:
    for (auto& child : children)
    {
        constexpr bool argument_with_disconnect = false;
        if (child->realign(outlines, rerooted_parts, argument_with_disconnect))
        {
            rerooted_parts.push_back(child);
        }
    }
    children.clear();

    if (connected_to_parent)
    {
        // This will now be a (new_ leaf:
        p = PolygonUtils::findClosest(p, outlines).p();
        return true;
    }

    return false;
}

void LightningTreeNode::straighten(const coord_t& magnitude)
{
    straighten(magnitude, p, 0);
}

LightningTreeNode::RectilinearJunction LightningTreeNode::straighten(const coord_t& magnitude, Point junction_above, coord_t accumulated_dist)
{
    if (children.size() == 1)
    {
        auto child_p = children.front();
        coord_t child_dist = vSize(p - child_p->p);
        RectilinearJunction junction_below = child_p->straighten(magnitude, junction_above, accumulated_dist + child_dist);
        coord_t total_dist_to_junction_below = junction_below.total_recti_dist;
        Point a = junction_above;
        Point b = junction_below.junction_loc;
        if (a != b) // should always be true!
        {
            Point ab = b - a;
            Point destination = a + ab * accumulated_dist / total_dist_to_junction_below;
            if (shorterThen(destination - p, magnitude))
            {
                p = destination;
            }
            else
            {
                p = p + normal(destination - p, magnitude);
            }
        }
        return junction_below;
    }
    else
    {
        for (auto child_p : children)
        {
            coord_t child_dist = vSize(p - child_p->p);
            child_p->straighten(magnitude, p, child_dist);
        }
        return RectilinearJunction{ accumulated_dist, p };
    }
}

// Prune the tree from the extremeties (leaf-nodes) until the pruning distance is reached.
coord_t LightningTreeNode::prune(const coord_t& pruning_distance)
{
    if (pruning_distance <= 0)
    {
        return 0;
    }

    coord_t max_distance_pruned = 0;
    for (auto child_it = children.begin(); child_it != children.end(); )
    {
        auto& child = *child_it;
        coord_t dist_pruned_child = child->prune(pruning_distance);
        if (dist_pruned_child >= pruning_distance)
        { // pruning is finished for child; dont modify further
            max_distance_pruned = std::max(max_distance_pruned, dist_pruned_child);
            ++child_it;
        }
        else
        {
            Point a = getLocation();
            Point b = child->getLocation();
            Point ba = a - b;
            coord_t ab_len = vSize(ba);
            if (dist_pruned_child + ab_len <= pruning_distance)
            { // we're still in the process of pruning
                assert(child->children.empty() && "when pruning away a node all it's children must already have been pruned away");
                max_distance_pruned = std::max(max_distance_pruned, dist_pruned_child + ab_len);
                child_it = children.erase(child_it);
            }
            else
            { // pruning stops in between this node and the child
                Point n = b + normal(ba, pruning_distance - dist_pruned_child);
                assert(std::abs(vSize(n - b) + dist_pruned_child - pruning_distance) < 10 && "total pruned distance must be equal to the pruning_distance");
                max_distance_pruned = std::max(max_distance_pruned, pruning_distance);
                child->setLocation(n);
                ++child_it;
            }
        }
    }

    return max_distance_pruned;
}
<commit_msg>junction smoothing<commit_after>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "LightningTree.h"

#include "../utils/linearAlg2D.h"

using namespace cura;

coord_t LightningTreeNode::getWeightedDistance(const Point& unsupported_loc, const coord_t& supporting_radius) const
{
    size_t valence = (!is_root) + children.size();
    coord_t boost = (0 < valence && valence < 4) ? 4 * supporting_radius : 0;
    return vSize(getLocation() - unsupported_loc) - boost;
}

bool LightningTreeNode::hasOffspring(const std::shared_ptr<LightningTreeNode>& to_be_checked) const
{
    if (to_be_checked == shared_from_this()) return true;
    for (auto child_ptr : children)
    {
        if (child_ptr->hasOffspring(to_be_checked)) return true;
    }
    return false;
}

const Point& LightningTreeNode::getLocation() const
{
    return p;
}

void LightningTreeNode::setLocation(const Point& loc)
{
    p = loc;
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::addChild(const Point& child_loc)
{
    assert(p != child_loc);
    children.push_back(LightningTreeNode::create(child_loc));
    return children.back();
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::addChild(std::shared_ptr<LightningTreeNode>& new_child)
{
    assert(new_child != shared_from_this());
    //     assert(p != new_child->p);
    if (p == new_child->p)
        std::cerr << "wtf\n";
    children.push_back(new_child);
    new_child->is_root = false;
    return new_child;
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::findClosestNode(const Point& x, const coord_t& supporting_radius)
{
    coord_t closest_distance = getWeightedDistance(x, supporting_radius);
    std::shared_ptr<LightningTreeNode> closest_node = shared_from_this();
    findClosestNodeHelper(x, supporting_radius, closest_distance, closest_node);
    return closest_node;
}

void LightningTreeNode::propagateToNextLayer
(
    std::vector<std::shared_ptr<LightningTreeNode>>& next_trees,
    const Polygons& next_outlines,
    const coord_t& prune_distance,
    const coord_t& smooth_magnitude
) const
{
    auto tree_below = deepCopy();

    // TODO: What is the correct order of the following operations?
    //       (NOTE: in case realign turns out _not_ to be last, would need to rewrite a few things, see the 'rerooted_parts' parameter of that function).
    tree_below->prune(prune_distance);
    tree_below->straighten(smooth_magnitude);
    if (tree_below->realign(next_outlines, next_trees))
    {
        next_trees.push_back(tree_below);
    }
}

// NOTE: Depth-first, as currently implemented.
//       Skips the root (because that has no root itself), but all initial nodes will have the root point anyway.
void LightningTreeNode::visitBranches(const branch_visitor_func_t& visitor) const
{
    for (const auto& node : children)
    {
        visitor(p, node->p);
        node->visitBranches(visitor);
    }
}

// NOTE: Depth-first, as currently implemented.
void LightningTreeNode::visitNodes(const node_visitor_func_t& visitor)
{
    visitor(shared_from_this());
    for (const auto& node : children)
    {
        node->visitNodes(visitor);
    }
}

// Node:
LightningTreeNode::LightningTreeNode(const Point& p) : is_root(false), p(p) {}

// Root (and Trunk):
LightningTreeNode::LightningTreeNode(const Point& a, const Point& b) : LightningTreeNode(a)
{
    children.push_back(LightningTreeNode::create(b));
    is_root = true;
}

void LightningTreeNode::findClosestNodeHelper(const Point& x, const coord_t supporting_radius, coord_t& closest_distance, std::shared_ptr<LightningTreeNode>& closest_node)
{
    for (const auto& node : children)
    {
        node->findClosestNodeHelper(x, supporting_radius, closest_distance, closest_node);
        const coord_t distance = node->getWeightedDistance(x, supporting_radius);
        if (distance < closest_distance)
        {
            closest_node = node;
            closest_distance = distance;
        }
    }
}

std::shared_ptr<LightningTreeNode> LightningTreeNode::deepCopy() const
{
    std::shared_ptr<LightningTreeNode> local_root = LightningTreeNode::create(p);
    local_root->is_root = is_root;
    local_root->children.reserve(children.size());
    for (const auto& node : children)
    {
        local_root->children.push_back(node->deepCopy());
    }
    return local_root;
}

bool LightningTreeNode::realign(const Polygons& outlines, std::vector<std::shared_ptr<LightningTreeNode>>& rerooted_parts, const bool& connected_to_parent)
{
    // TODO: Hole(s) in the _middle_ of a line-segement, not unlikely since reconnect.
    // TODO: Reconnect if not on outline -> plan is: yes, but not here anymore!

    if (outlines.empty())
    {
        return false;
    }

    if (outlines.inside(p, true))
    {
        // Only keep children that have an unbroken connection to here, realign will put the rest in rerooted parts due to recursion:
        const std::function<bool(const std::shared_ptr<LightningTreeNode>& child)> remove_unconnected_func
        (
            [&outlines, &rerooted_parts](const std::shared_ptr<LightningTreeNode>& child)
            {
                constexpr bool argument_with_connected = true;
                return !child->realign(outlines, rerooted_parts, argument_with_connected);
            }
        );
        children.erase(std::remove_if(children.begin(), children.end(), remove_unconnected_func), children.end());
        return true;
    }

    // 'Lift' any decendants out of this tree:
    for (auto& child : children)
    {
        constexpr bool argument_with_disconnect = false;
        if (child->realign(outlines, rerooted_parts, argument_with_disconnect))
        {
            rerooted_parts.push_back(child);
        }
    }
    children.clear();

    if (connected_to_parent)
    {
        // This will now be a (new_ leaf:
        p = PolygonUtils::findClosest(p, outlines).p();
        return true;
    }

    return false;
}

void LightningTreeNode::straighten(const coord_t& magnitude)
{
    straighten(magnitude, p, 0);
}

LightningTreeNode::RectilinearJunction LightningTreeNode::straighten(const coord_t& magnitude, Point junction_above, coord_t accumulated_dist)
{
    const coord_t junction_magnitude = magnitude * 3 / 4;
    if (children.size() == 1)
    {
        auto child_p = children.front();
        coord_t child_dist = vSize(p - child_p->p);
        RectilinearJunction junction_below = child_p->straighten(magnitude, junction_above, accumulated_dist + child_dist);
        coord_t total_dist_to_junction_below = junction_below.total_recti_dist;
        Point a = junction_above;
        Point b = junction_below.junction_loc;
        if (a != b) // should always be true!
        {
            Point ab = b - a;
            Point destination = a + ab * accumulated_dist / total_dist_to_junction_below;
            if (shorterThen(destination - p, magnitude))
            {
                p = destination;
            }
            else
            {
                p = p + normal(destination - p, magnitude);
            }
        }
        return junction_below;
    }
    else
    {
        Point junction_moving_dir = normal(junction_above - p, accumulated_dist);
        for (auto child_p : children)
        {
            coord_t child_dist = vSize(p - child_p->p);
            RectilinearJunction below = child_p->straighten(magnitude, p, child_dist);

            junction_moving_dir += normal(below.junction_loc - p, below.total_recti_dist);
        }
        if (junction_moving_dir != Point(0, 0) && ! children.empty())
        {
            coord_t junction_moving_dir_len = vSize(junction_moving_dir);
            if (junction_moving_dir_len > junction_magnitude)
            {
                junction_moving_dir = junction_moving_dir * junction_magnitude / junction_moving_dir_len;
            }
            p += junction_moving_dir;
        }
        return RectilinearJunction{ accumulated_dist, p };
    }
}

// Prune the tree from the extremeties (leaf-nodes) until the pruning distance is reached.
coord_t LightningTreeNode::prune(const coord_t& pruning_distance)
{
    if (pruning_distance <= 0)
    {
        return 0;
    }

    coord_t max_distance_pruned = 0;
    for (auto child_it = children.begin(); child_it != children.end(); )
    {
        auto& child = *child_it;
        coord_t dist_pruned_child = child->prune(pruning_distance);
        if (dist_pruned_child >= pruning_distance)
        { // pruning is finished for child; dont modify further
            max_distance_pruned = std::max(max_distance_pruned, dist_pruned_child);
            ++child_it;
        }
        else
        {
            Point a = getLocation();
            Point b = child->getLocation();
            Point ba = a - b;
            coord_t ab_len = vSize(ba);
            if (dist_pruned_child + ab_len <= pruning_distance)
            { // we're still in the process of pruning
                assert(child->children.empty() && "when pruning away a node all it's children must already have been pruned away");
                max_distance_pruned = std::max(max_distance_pruned, dist_pruned_child + ab_len);
                child_it = children.erase(child_it);
            }
            else
            { // pruning stops in between this node and the child
                Point n = b + normal(ba, pruning_distance - dist_pruned_child);
                assert(std::abs(vSize(n - b) + dist_pruned_child - pruning_distance) < 10 && "total pruned distance must be equal to the pruning_distance");
                max_distance_pruned = std::max(max_distance_pruned, pruning_distance);
                child->setLocation(n);
                ++child_it;
            }
        }
    }

    return max_distance_pruned;
}
<|endoftext|>


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

#ifndef TYPE_TRAITS_H
#define TYPE_TRAITS_H

#include <types.hpp>
#include <enable_if.hpp>

namespace std {

template <typename T>
struct iterator_traits {
    using value_type      = typename T::value_type;
    using reference       = typename T::reference;
    using pointer         = typename T::pointer;
    using difference_type = typename T::difference_type;
};

template <typename T>
struct iterator_traits <T*> {
    using value_type      = T;
    using reference       = T&;
    using pointer         = T*;
    using difference_type = size_t;
};

template<class T>
struct remove_reference {
    typedef T type;
};

template<class T>
struct remove_reference<T&>{
    typedef T type;
};

template<class T>
struct remove_reference<T&&> {
    typedef T type;
};

/* remove_extent */

template<class T>
struct remove_extent {
    typedef T type;
};

template<class T>
struct remove_extent<T[]> {
    typedef T type;
};

template<class T, size_t N>
struct remove_extent<T[N]> {
    typedef T type;
};

/* remove_const */

template<class T>
struct remove_const {
    typedef T type;
};

template<class T>
struct remove_const<const T> {
    typedef T type;
};

/* remove_volatile */

template<class T>
struct remove_volatile {
    typedef T type;
};

template<class T>
struct remove_volatile<volatile T> {
    typedef T type;
};

/* remove_cv */

template<class T>
struct remove_cv {
    typedef typename std::remove_volatile<typename std::remove_const<T>::type>::type type;
};

/* conditional */

template<bool B, class T, class F>
struct conditional {
    typedef T type;
};

template<class T, class F>
struct conditional<false, T, F> {
    typedef F type;
};

template<bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;

/* is_trivially_destructible */

template<typename T>
struct is_trivially_destructible {
    static constexpr const bool value = __has_trivial_destructor(T);
};

/* is_trivially_destructible */

template<typename T>
struct has_trivial_assign {
    static constexpr const bool value = __has_trivial_assign(T);
};

/* is_reference */

template <typename T>
struct is_reference {
    static constexpr const bool value = false;
};

template <typename T>
struct is_reference<T&>{
    static constexpr const bool value = true;
};

template <typename T>
struct is_reference<T&&>{
    static constexpr const bool value = true;
};

/* is_array */

template<class T>
struct is_array {
    static constexpr const bool value = false;
};

template<class T>
struct is_array<T[]>{
    static constexpr const bool value = true;
};

template<class T, size_t N>
struct is_array<T[N]>{
    static constexpr const bool value = true;
};

/* is_function */

template<typename T>
struct is_function {
    static constexpr const bool value = false;
};

template<class Ret, class... Args>
struct is_function<Ret(Args...)> {
    static constexpr const bool value = true;
};

template<class Ret, class... Args>
struct is_function<Ret(Args......)> {
    static constexpr const bool value = true;
};

/* add_rvalue_reference */

template<typename T, typename Enable = void>
struct add_rvalue_reference;

template<typename T>
struct add_rvalue_reference<T, typename std::enable_if_t<std::is_reference<T>::value>> {
    typedef T type;
};

template<typename T>
struct add_rvalue_reference<T, typename std::disable_if_t<!std::is_reference<T>::value>> {
    typedef T&& type;
};

/* add_pointer */

template<typename T>
struct add_pointer {
    typedef typename std::remove_reference<T>::type* type;
};

/* decay */

template<typename T>
struct decay {
    typedef typename std::remove_reference<T>::type U;
    typedef typename std::conditional<
        std::is_array<U>::value,
        typename std::remove_extent<U>::type*,
        typename std::conditional<
            std::is_function<U>::value,
            typename std::add_pointer<U>::type,
            typename std::remove_cv<U>::type
        >::type
    >::type type;
};

/* is_same */

template<typename T1, typename T2>
struct is_same {
    static constexpr const bool value = false;
};

template<typename T1>
struct is_same <T1, T1> {
    static constexpr const bool value = true;
};

} //end of namespace std

#endif
<commit_msg>Fix is_trivially_destructible for void<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#ifndef TYPE_TRAITS_H
#define TYPE_TRAITS_H

#include <types.hpp>
#include <enable_if.hpp>

namespace std {

template <typename T>
struct iterator_traits {
    using value_type      = typename T::value_type;
    using reference       = typename T::reference;
    using pointer         = typename T::pointer;
    using difference_type = typename T::difference_type;
};

template <typename T>
struct iterator_traits <T*> {
    using value_type      = T;
    using reference       = T&;
    using pointer         = T*;
    using difference_type = size_t;
};

template<class T>
struct remove_reference {
    typedef T type;
};

template<class T>
struct remove_reference<T&>{
    typedef T type;
};

template<class T>
struct remove_reference<T&&> {
    typedef T type;
};

/* remove_extent */

template<class T>
struct remove_extent {
    typedef T type;
};

template<class T>
struct remove_extent<T[]> {
    typedef T type;
};

template<class T, size_t N>
struct remove_extent<T[N]> {
    typedef T type;
};

/* remove_const */

template<class T>
struct remove_const {
    typedef T type;
};

template<class T>
struct remove_const<const T> {
    typedef T type;
};

/* remove_volatile */

template<class T>
struct remove_volatile {
    typedef T type;
};

template<class T>
struct remove_volatile<volatile T> {
    typedef T type;
};

/* remove_cv */

template<class T>
struct remove_cv {
    typedef typename std::remove_volatile<typename std::remove_const<T>::type>::type type;
};

/* conditional */

template<bool B, class T, class F>
struct conditional {
    typedef T type;
};

template<class T, class F>
struct conditional<false, T, F> {
    typedef F type;
};

template<bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;

/* is_trivially_destructible */

template<typename T>
struct is_trivially_destructible {
    static constexpr const bool value = __has_trivial_destructor(T);
};

template<>
struct is_trivially_destructible<void> {
    static constexpr const bool value = true;
};

/* is_trivially_destructible */

template<typename T>
struct has_trivial_assign {
    static constexpr const bool value = __has_trivial_assign(T);
};

/* is_reference */

template <typename T>
struct is_reference {
    static constexpr const bool value = false;
};

template <typename T>
struct is_reference<T&>{
    static constexpr const bool value = true;
};

template <typename T>
struct is_reference<T&&>{
    static constexpr const bool value = true;
};

/* is_array */

template<class T>
struct is_array {
    static constexpr const bool value = false;
};

template<class T>
struct is_array<T[]>{
    static constexpr const bool value = true;
};

template<class T, size_t N>
struct is_array<T[N]>{
    static constexpr const bool value = true;
};

/* is_function */

template<typename T>
struct is_function {
    static constexpr const bool value = false;
};

template<class Ret, class... Args>
struct is_function<Ret(Args...)> {
    static constexpr const bool value = true;
};

template<class Ret, class... Args>
struct is_function<Ret(Args......)> {
    static constexpr const bool value = true;
};

/* add_rvalue_reference */

template<typename T, typename Enable = void>
struct add_rvalue_reference;

template<typename T>
struct add_rvalue_reference<T, typename std::enable_if_t<std::is_reference<T>::value>> {
    typedef T type;
};

template<typename T>
struct add_rvalue_reference<T, typename std::disable_if_t<!std::is_reference<T>::value>> {
    typedef T&& type;
};

/* add_pointer */

template<typename T>
struct add_pointer {
    typedef typename std::remove_reference<T>::type* type;
};

/* decay */

template<typename T>
struct decay {
    typedef typename std::remove_reference<T>::type U;
    typedef typename std::conditional<
        std::is_array<U>::value,
        typename std::remove_extent<U>::type*,
        typename std::conditional<
            std::is_function<U>::value,
            typename std::add_pointer<U>::type,
            typename std::remove_cv<U>::type
        >::type
    >::type type;
};

/* is_same */

template<typename T1, typename T2>
struct is_same {
    static constexpr const bool value = false;
};

template<typename T1>
struct is_same <T1, T1> {
    static constexpr const bool value = true;
};

} //end of namespace std

#endif
<|endoftext|>


<commit_before>#include <QMainWindow>
#include <QFileDialog>
#include <QString>
#include <QBoxLayout>
#include <QLabel>
#include <QMessageBox>

#include "mainwindow.h"
#include "parser/htmlreader.h"
#include "painter/paintarea.h"

MainWindow::MainWindow()
{

    reader = new HTMLReader;
    webpage = new Document;

    //Draw main window for WebWhirr.
    setMinimumHeight(400);
    setMinimumWidth(600);

    positionSet = false;

    QLabel *addressBarLabel = new QLabel(tr("Current Document:"));
    addressBar = new QLineEdit;
    addressBar->setReadOnly(true);

    QHBoxLayout *addressBarLayout = new QHBoxLayout;
    addressBarLayout->addWidget(addressBarLabel);
    addressBarLayout->addWidget(addressBar);

    paintArea = new PaintArea;
    scrollArea = new QScrollArea(this);
    documentDisplay = new QLabel(scrollArea);

    documentDisplay->setAlignment(Qt::AlignTop | Qt::AlignLeft);

    scrollArea->setWidget(documentDisplay);
    scrollArea->setWidgetResizable(true);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addLayout(addressBarLayout);
    layout->addWidget(scrollArea);

    centralLayout = new QWidget;
    centralLayout->setLayout(layout);

    setCentralWidget(centralLayout);

    createActions();
    createMenus();

    setWindowTitle("WebWhirr 0.1 Beta");

}

void MainWindow::createActions()
{
    openAct = new QAction(tr("&Open"), this);
    openAct->setShortcut(QKeySequence::Open);

    connect(openAct, SIGNAL(triggered()), this, SLOT(setFilepath()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
}

bool MainWindow::setFilepath(std::string filepath)
{
    if (!checkFilepath(filepath))
    {
        return false;
    }
    else
    {
        //Construct a Document (contains node tree) from parsing document
        //passed from command line.
        webpage = reader->prepareDocument(filepath);
        addressBar->setText(QString::fromStdString(filepath));

        paintArea->setDocument(webpage);
    }

    return true;
}

bool MainWindow::setFilepath()
{
    //QString::toStdString() doesn't convert the filepath properly
    std::string filepath = QFileDialog::getOpenFileName(this,
                                                        tr("Open HTML Document")).toUtf8().constData();
    if (filepath.empty())
    {
        return false;
    }

    if (!checkFilepath(filepath))
    {
        QMessageBox invalidTypeErrorBox;
        invalidTypeErrorBox.setText("Error: Document type is invalid or not supported.");
        invalidTypeErrorBox.exec();
        return false;
    }

    else
    {
        //Delete any old nodes to avoid memory leaks.
        if (webpage->getFirstNode() != NULL)
        {
            webpage->clearTree();
        }

        addressBar->setText(QString::fromStdString(filepath));

        //Construct a Document (contains node tree) from parsing document
        //selected in "Open HTML Document" dialog.
        webpage = reader->prepareDocument(filepath);

        paintArea->setDocument(webpage);

        return repaintDocument();
    }
}

bool MainWindow::repaintDocument()
{
    //Paint the current document in paintArea by creating a QPixmap
    //and assigning this to the QLabel documentDisplay. Dimensions
    //are also set to avoid annoying issues with the scrollbars.
    QPixmap paintedDocument = paintArea->grab();
    documentDisplay->setMinimumWidth(paintedDocument.width());
    documentDisplay->setMaximumWidth(paintedDocument.width());
    documentDisplay->setMaximumHeight(paintArea->height());
    documentDisplay->setPixmap(paintedDocument);
    scrollArea->setMinimumWidth(documentDisplay->width() + 20);
    this->setMinimumWidth(scrollArea->width() + 20);
    return true;
}

bool MainWindow::checkFilepath(std::string filepath)
{
    //This is a fix for the crash on opening a non-HTML document.
    //It will have to do until I write a check into the encoding,
    //because for some reason a similar check in the document text
    //itself always returns true.
    if (filepath.find(".html") != std::string::npos ||
            filepath.find(".htm") != std::string::npos)
    {
        return true;
    }

    return false;
}

Document* MainWindow::getWebpage()
{
    return webpage;
}
<commit_msg>Fix issue 23: Must open document twice to be able to scroll through.<commit_after>#include <QMainWindow>
#include <QFileDialog>
#include <QString>
#include <QBoxLayout>
#include <QLabel>
#include <QMessageBox>

#include "mainwindow.h"
#include "parser/htmlreader.h"
#include "painter/paintarea.h"

MainWindow::MainWindow()
{

    reader = new HTMLReader;
    webpage = new Document;

    //Draw main window for WebWhirr.
    setMinimumHeight(480);
    setMinimumWidth(640);

    positionSet = false;

    QLabel *addressBarLabel = new QLabel(tr("Current Document:"));
    addressBar = new QLineEdit;
    addressBar->setReadOnly(true);

    QHBoxLayout *addressBarLayout = new QHBoxLayout;
    addressBarLayout->addWidget(addressBarLabel);
    addressBarLayout->addWidget(addressBar);

    paintArea = new PaintArea;
    scrollArea = new QScrollArea(this);
    documentDisplay = new QLabel(scrollArea);

    documentDisplay->setAlignment(Qt::AlignTop | Qt::AlignLeft);

    scrollArea->setWidget(documentDisplay);
    scrollArea->setWidgetResizable(true);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addLayout(addressBarLayout);
    layout->addWidget(scrollArea);

    centralLayout = new QWidget;
    centralLayout->setLayout(layout);

    setCentralWidget(centralLayout);

    createActions();
    createMenus();

    setWindowTitle("WebWhirr 0.1 Beta");

}

void MainWindow::createActions()
{
    openAct = new QAction(tr("&Open"), this);
    openAct->setShortcut(QKeySequence::Open);

    connect(openAct, SIGNAL(triggered()), this, SLOT(setFilepath()));
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
}

bool MainWindow::setFilepath(std::string filepath)
{
    if (!checkFilepath(filepath))
    {
        return false;
    }
    else
    {
        //Construct a Document (contains node tree) from parsing document
        //passed from command line.
        webpage = reader->prepareDocument(filepath);
        addressBar->setText(QString::fromStdString(filepath));

        paintArea->setDocument(webpage);
    }

    return true;
}

bool MainWindow::setFilepath()
{
    //QString::toStdString() doesn't convert the filepath properly
    std::string filepath = QFileDialog::getOpenFileName(this,
                                                        tr("Open HTML Document")).toUtf8().constData();
    if (filepath.empty())
    {
        return false;
    }

    if (!checkFilepath(filepath))
    {
        QMessageBox invalidTypeErrorBox;
        invalidTypeErrorBox.setText("Error: Document type is invalid or not supported.");
        invalidTypeErrorBox.exec();
        return false;
    }

    else
    {
        //Delete any old nodes to avoid memory leaks.
        if (webpage->getFirstNode() != NULL)
        {
            webpage->clearTree();
        }

        addressBar->setText(QString::fromStdString(filepath));

        //Construct a Document (contains node tree) from parsing document
        //selected in "Open HTML Document" dialog.
        webpage = reader->prepareDocument(filepath);

        paintArea->setDocument(webpage);

        return repaintDocument();
    }
}

//This entire function is a mess. I will return and work
//on it more after the 0.1.0 release.
bool MainWindow::repaintDocument()
{
    //Paint the current document in paintArea by creating a QPixmap
    //and assigning this to the QLabel documentDisplay. Dimensions
    //are also set to avoid annoying issues with the scrollbars.
    QPixmap paintedDocument;
    paintArea->update();

    //grab() has to be called twice. Otherwise, the pixmap is the wrong
    //size when the document is first displayed and the document has to
    //be opened twice in order to scroll through it properly.
    paintedDocument = paintArea->grab();
    paintedDocument.scaled(paintArea->size(), Qt::IgnoreAspectRatio);
    paintedDocument = paintArea->grab();

    documentDisplay->setMinimumWidth(paintedDocument.width());
    documentDisplay->setMaximumWidth(paintedDocument.width());
    documentDisplay->setMaximumHeight(paintArea->height());

    documentDisplay->setPixmap(paintedDocument);
    scrollArea->setMinimumWidth(documentDisplay->width() + 20);
    this->setMinimumWidth(scrollArea->width() + 20);

    return true;
}

bool MainWindow::checkFilepath(std::string filepath)
{
    //This is a fix for the crash on opening a non-HTML document.
    //It will have to do until I write a check into the encoding,
    //because for some reason a similar check in the document text
    //itself always returns true.
    if (filepath.find(".html") != std::string::npos ||
            filepath.find(".htm") != std::string::npos)
    {
        return true;
    }

    return false;
}

Document* MainWindow::getWebpage()
{
    return webpage;
}
<|endoftext|>