<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ForwardHttpRequest.hxx"
#include "lb_instance.hxx"
#include "lb_connection.hxx"
#include "lb_config.hxx"
#include "lb_session.hxx"
#include "lb_cookie.hxx"
#include "lb_jvm_route.hxx"
#include "lb_headers.hxx"
#include "lb_log.hxx"
#include "ssl/ssl_filter.hxx"
#include "address_sticky.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_client.hxx"
#include "tcp_stock.hxx"
#include "tcp_balancer.hxx"
#include "http_response.hxx"
#include "http_headers.hxx"
#include "stock/GetHandler.hxx"
#include "stock/Item.hxx"
#include "stock/Lease.hxx"
#include "strmap.hxx"
#include "failure.hxx"
#include "bulldog.hxx"
#include "pool.hxx"
#include "net/SocketAddress.hxx"
#include "net/SocketDescriptor.hxx"
#include "istream/istream.hxx"
#include "istream/UnusedHoldPtr.hxx"
#include "util/Cancellable.hxx"

struct LbRequest final
    : Cancellable, StockGetHandler, HttpResponseHandler {

    LbConnection &connection;
    const LbClusterConfig &cluster_config;

    TcpBalancer &balancer;

    HttpServerRequest &request;

    /**
     * The request body.
     */
    UnusedHoldIstreamPtr body;

    CancellablePointer cancel_ptr;

    StockItem *stock_item;

    unsigned new_cookie = 0;

    LbRequest(LbConnection &_connection, const LbClusterConfig &_cluster_config,
              TcpBalancer &_balancer,
              HttpServerRequest &_request,
              CancellablePointer &_cancel_ptr)
        :connection(_connection), cluster_config(_cluster_config),
         balancer(_balancer),
         request(_request),
         body(request.pool, request.body) {
        _cancel_ptr = *this;
    }

    void Destroy() {
        DeleteFromPool(request.pool, this);
    }

    sticky_hash_t GetStickyHash();
    sticky_hash_t MakeCookieHash();

    /* virtual methods from class Cancellable */
    void Cancel() override {
        body.Clear();
        CancellablePointer c(std::move(cancel_ptr));
        Destroy();
        c.Cancel();
    }

    /* virtual methods from class StockGetHandler */
    void OnStockItemReady(StockItem &item) override;
    void OnStockItemError(GError *error) override;

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        Istream *body) override;
    void OnHttpError(GError *error) override;
};

static void
SendResponse(HttpServerRequest &request,
             const LbSimpleHttpResponse &response)
{
    assert(response.IsDefined());

    http_server_simple_response(request, response.status,
                                response.location.empty() ? nullptr : response.location.c_str(),
                                response.message.empty() ? nullptr : response.message.c_str());
}

static bool
send_fallback(HttpServerRequest &request,
              const LbSimpleHttpResponse &fallback)
{
    if (!fallback.IsDefined())
        return false;

    SendResponse(request, fallback);
    return true;
}

/**
 * Generate a cookie for sticky worker selection.  Return only worker
 * numbers that are not known to be failing.  Returns 0 on total
 * failure.
 */
static unsigned
generate_cookie(const AddressList *list)
{
    assert(list->GetSize() >= 2);

    const unsigned first = lb_cookie_generate(list->GetSize());

    unsigned i = first;
    do {
        assert(i >= 1 && i <= list->GetSize());
        const SocketAddress address = list->addresses[i % list->GetSize()];
        if (failure_get_status(address) == FAILURE_OK &&
            bulldog_check(address) && !bulldog_is_fading(address))
            return i;

        i = lb_cookie_next(list->GetSize(), i);
    } while (i != first);

    /* all nodes have failed */
    return first;
}

sticky_hash_t
LbRequest::MakeCookieHash()
{
    unsigned hash = lb_cookie_get(request.headers);
    if (hash == 0)
        new_cookie = hash = generate_cookie(&cluster_config.address_list);

    return hash;
}

sticky_hash_t
LbRequest::GetStickyHash()
{
    switch (cluster_config.sticky_mode) {
    case StickyMode::NONE:
    case StickyMode::FAILOVER:
        /* these modes require no preparation; they are handled
           completely by balancer_get() */
        return 0;

    case StickyMode::SOURCE_IP:
        /* calculate session_sticky from remote address */
        return socket_address_sticky(request.remote_address);

    case StickyMode::SESSION_MODULO:
        /* calculate session_sticky from beng-proxy session id */
        return lb_session_get(request.headers,
                              cluster_config.session_cookie.c_str());

    case StickyMode::COOKIE:
        /* calculate session_sticky from beng-lb cookie */
        return MakeCookieHash();

    case StickyMode::JVM_ROUTE:
        /* calculate session_sticky from JSESSIONID cookie suffix */
        return lb_jvm_route_get(request.headers, cluster_config);
    }

    assert(false);
    gcc_unreachable();
}

/**
 * Is the specified error a server failure, that justifies
 * blacklisting the server for a while?
 */
static bool
is_server_failure(GError *error)
{
    return error->domain == http_client_quark() &&
        error->code != HTTP_CLIENT_UNSPECIFIED;
}

/*
 * HTTP response handler
 *
 */

void
LbRequest::OnHttpResponse(http_status_t status, StringMap &&_headers,
                          Istream *response_body)
{
    HttpHeaders headers(std::move(_headers));

    if (request.method == HTTP_METHOD_HEAD)
        /* pass Content-Length, even though there is no response body
           (RFC 2616 14.13) */
        headers.MoveToBuffer("content-length");

    if (new_cookie != 0) {
        char buffer[64];
        /* "Discard" must be last, to work around an Android bug*/
        snprintf(buffer, sizeof(buffer),
                 "beng_lb_node=0-%x; HttpOnly; Path=/; Version=1; Discard",
                 new_cookie);

        headers.Write("cookie2", "$Version=\"1\"");
        headers.Write("set-cookie", buffer);
    }

    http_server_response(&request, status, std::move(headers), response_body);
    Destroy();
}

void
LbRequest::OnHttpError(GError *error)
{
    if (is_server_failure(error))
        failure_add(tcp_stock_item_get_address(*stock_item));

    lb_connection_log_gerror(2, &connection, "Error", error);

    if (!send_fallback(request, cluster_config.fallback)) {
        const char *msg = connection.listener.verbose_response
            ? error->message
            : "Server failure";

        http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY, msg);
    }

    g_error_free(error);
    Destroy();
}

/*
 * stock callback
 *
 */

void
LbRequest::OnStockItemReady(StockItem &item)
{
    stock_item = &item;

    const char *peer_subject = connection.ssl_filter != nullptr
        ? ssl_filter_get_peer_subject(connection.ssl_filter)
        : nullptr;
    const char *peer_issuer_subject = connection.ssl_filter != nullptr
        ? ssl_filter_get_peer_issuer_subject(connection.ssl_filter)
        : nullptr;

    auto &headers = request.headers;
    lb_forward_request_headers(request.pool, headers,
                               request.local_host_and_port,
                               request.remote_host,
                               peer_subject, peer_issuer_subject,
                               cluster_config.mangle_via);

    auto *lease = NewFromPool<StockItemLease>(request.pool, item);

    http_client_request(request.pool,
                        connection.instance.event_loop,
                        tcp_stock_item_get(item),
                        tcp_stock_item_get_domain(item) == AF_LOCAL
                        ? FdType::FD_SOCKET : FdType::FD_TCP,
                        *lease,
                        item.GetStockName(),
                        NULL, NULL,
                        request.method, request.uri,
                        HttpHeaders(std::move(headers)),
                        body.Steal(), true,
                        *this, cancel_ptr);
}

void
LbRequest::OnStockItemError(GError *error)
{
    lb_connection_log_gerror(2, &connection, "Connect error", error);

    body.Clear();

    if (!send_fallback(request, cluster_config.fallback)) {
        const char *msg = connection.listener.verbose_response
            ? error->message
            : "Connection failure";

        http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY,
                                 msg);
    }

    g_error_free(error);
}

/*
 * constructor
 *
 */

void
ForwardHttpRequest(LbConnection &connection,
                   HttpServerRequest &request,
                   const LbClusterConfig &cluster_config,
                   CancellablePointer &cancel_ptr)
{
    const auto request2 =
        NewFromPool<LbRequest>(request.pool,
                               connection, cluster_config,
                               *connection.instance.tcp_balancer,
                               request, cancel_ptr);

    SocketAddress bind_address = SocketAddress::Null();
    const bool transparent_source = cluster_config.transparent_source;
    if (transparent_source) {
        bind_address = request.remote_address;

        /* reset the port to 0 to allow the kernel to choose one */
        if (bind_address.GetFamily() == AF_INET) {
            struct sockaddr_in *s_in = (struct sockaddr_in *)
                p_memdup(&request.pool, bind_address.GetAddress(),
                         bind_address.GetSize());
            s_in->sin_port = 0;
            bind_address = SocketAddress((const struct sockaddr *)s_in,
                                         bind_address.GetSize());
        } else if (bind_address.GetFamily() == AF_INET6) {
            struct sockaddr_in6 *s_in = (struct sockaddr_in6 *)
                p_memdup(&request.pool, bind_address.GetAddress(),
                         bind_address.GetSize());
            s_in->sin6_port = 0;
            bind_address = SocketAddress((const struct sockaddr *)s_in,
                                         bind_address.GetSize());
        }
    }

    if (cluster_config.HasZeroConf()) {
        /* TODO: generalize the Zeroconf code, implement sticky */

        auto *cluster2 = connection.instance.clusters.Find(cluster_config.name);
        if (cluster2 == nullptr) {
            http_server_send_message(&request,
                                     HTTP_STATUS_INTERNAL_SERVER_ERROR,
                                     "Zeroconf cluster not found");
            return;
        }

        const auto member = cluster2->Pick(request2->GetStickyHash());
        if (member.first == nullptr) {
            http_server_send_message(&request,
                                     HTTP_STATUS_INTERNAL_SERVER_ERROR,
                                     "Zeroconf cluster is empty");
            return;
        }

        assert(member.second.IsDefined());

        tcp_stock_get(*connection.instance.tcp_stock, request.pool,
                      member.first,
                      transparent_source, bind_address,
                      member.second,
                      20,
                      *request2, request2->cancel_ptr);

        return;
    }

    tcp_balancer_get(request2->balancer, request.pool,
                     transparent_source,
                     bind_address,
                     request2->GetStickyHash(),
                     cluster_config.address_list,
                     20,
                     *request2, request2->cancel_ptr);
}
<commit_msg>lb/ForwardHttpRequest: move code to method Start()<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ForwardHttpRequest.hxx"
#include "lb_instance.hxx"
#include "lb_connection.hxx"
#include "lb_config.hxx"
#include "lb_session.hxx"
#include "lb_cookie.hxx"
#include "lb_jvm_route.hxx"
#include "lb_headers.hxx"
#include "lb_log.hxx"
#include "ssl/ssl_filter.hxx"
#include "address_sticky.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_client.hxx"
#include "tcp_stock.hxx"
#include "tcp_balancer.hxx"
#include "http_response.hxx"
#include "http_headers.hxx"
#include "stock/GetHandler.hxx"
#include "stock/Item.hxx"
#include "stock/Lease.hxx"
#include "strmap.hxx"
#include "failure.hxx"
#include "bulldog.hxx"
#include "pool.hxx"
#include "net/SocketAddress.hxx"
#include "net/SocketDescriptor.hxx"
#include "istream/istream.hxx"
#include "istream/UnusedHoldPtr.hxx"
#include "util/Cancellable.hxx"

struct LbRequest final
    : Cancellable, StockGetHandler, HttpResponseHandler {

    LbConnection &connection;
    const LbClusterConfig &cluster_config;

    TcpBalancer &balancer;

    HttpServerRequest &request;

    /**
     * The request body.
     */
    UnusedHoldIstreamPtr body;

    CancellablePointer cancel_ptr;

    StockItem *stock_item;

    unsigned new_cookie = 0;

    LbRequest(LbConnection &_connection, const LbClusterConfig &_cluster_config,
              TcpBalancer &_balancer,
              HttpServerRequest &_request,
              CancellablePointer &_cancel_ptr)
        :connection(_connection), cluster_config(_cluster_config),
         balancer(_balancer),
         request(_request),
         body(request.pool, request.body) {
        _cancel_ptr = *this;
    }

    void Start();

    void Destroy() {
        DeleteFromPool(request.pool, this);
    }

    sticky_hash_t GetStickyHash();
    sticky_hash_t MakeCookieHash();

    /* virtual methods from class Cancellable */
    void Cancel() override {
        body.Clear();
        CancellablePointer c(std::move(cancel_ptr));
        Destroy();
        c.Cancel();
    }

    /* virtual methods from class StockGetHandler */
    void OnStockItemReady(StockItem &item) override;
    void OnStockItemError(GError *error) override;

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        Istream *body) override;
    void OnHttpError(GError *error) override;
};

static void
SendResponse(HttpServerRequest &request,
             const LbSimpleHttpResponse &response)
{
    assert(response.IsDefined());

    http_server_simple_response(request, response.status,
                                response.location.empty() ? nullptr : response.location.c_str(),
                                response.message.empty() ? nullptr : response.message.c_str());
}

static bool
send_fallback(HttpServerRequest &request,
              const LbSimpleHttpResponse &fallback)
{
    if (!fallback.IsDefined())
        return false;

    SendResponse(request, fallback);
    return true;
}

/**
 * Generate a cookie for sticky worker selection.  Return only worker
 * numbers that are not known to be failing.  Returns 0 on total
 * failure.
 */
static unsigned
generate_cookie(const AddressList *list)
{
    assert(list->GetSize() >= 2);

    const unsigned first = lb_cookie_generate(list->GetSize());

    unsigned i = first;
    do {
        assert(i >= 1 && i <= list->GetSize());
        const SocketAddress address = list->addresses[i % list->GetSize()];
        if (failure_get_status(address) == FAILURE_OK &&
            bulldog_check(address) && !bulldog_is_fading(address))
            return i;

        i = lb_cookie_next(list->GetSize(), i);
    } while (i != first);

    /* all nodes have failed */
    return first;
}

sticky_hash_t
LbRequest::MakeCookieHash()
{
    unsigned hash = lb_cookie_get(request.headers);
    if (hash == 0)
        new_cookie = hash = generate_cookie(&cluster_config.address_list);

    return hash;
}

sticky_hash_t
LbRequest::GetStickyHash()
{
    switch (cluster_config.sticky_mode) {
    case StickyMode::NONE:
    case StickyMode::FAILOVER:
        /* these modes require no preparation; they are handled
           completely by balancer_get() */
        return 0;

    case StickyMode::SOURCE_IP:
        /* calculate session_sticky from remote address */
        return socket_address_sticky(request.remote_address);

    case StickyMode::SESSION_MODULO:
        /* calculate session_sticky from beng-proxy session id */
        return lb_session_get(request.headers,
                              cluster_config.session_cookie.c_str());

    case StickyMode::COOKIE:
        /* calculate session_sticky from beng-lb cookie */
        return MakeCookieHash();

    case StickyMode::JVM_ROUTE:
        /* calculate session_sticky from JSESSIONID cookie suffix */
        return lb_jvm_route_get(request.headers, cluster_config);
    }

    assert(false);
    gcc_unreachable();
}

/**
 * Is the specified error a server failure, that justifies
 * blacklisting the server for a while?
 */
static bool
is_server_failure(GError *error)
{
    return error->domain == http_client_quark() &&
        error->code != HTTP_CLIENT_UNSPECIFIED;
}

/*
 * HTTP response handler
 *
 */

void
LbRequest::OnHttpResponse(http_status_t status, StringMap &&_headers,
                          Istream *response_body)
{
    HttpHeaders headers(std::move(_headers));

    if (request.method == HTTP_METHOD_HEAD)
        /* pass Content-Length, even though there is no response body
           (RFC 2616 14.13) */
        headers.MoveToBuffer("content-length");

    if (new_cookie != 0) {
        char buffer[64];
        /* "Discard" must be last, to work around an Android bug*/
        snprintf(buffer, sizeof(buffer),
                 "beng_lb_node=0-%x; HttpOnly; Path=/; Version=1; Discard",
                 new_cookie);

        headers.Write("cookie2", "$Version=\"1\"");
        headers.Write("set-cookie", buffer);
    }

    http_server_response(&request, status, std::move(headers), response_body);
    Destroy();
}

void
LbRequest::OnHttpError(GError *error)
{
    if (is_server_failure(error))
        failure_add(tcp_stock_item_get_address(*stock_item));

    lb_connection_log_gerror(2, &connection, "Error", error);

    if (!send_fallback(request, cluster_config.fallback)) {
        const char *msg = connection.listener.verbose_response
            ? error->message
            : "Server failure";

        http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY, msg);
    }

    g_error_free(error);
    Destroy();
}

/*
 * stock callback
 *
 */

void
LbRequest::OnStockItemReady(StockItem &item)
{
    stock_item = &item;

    const char *peer_subject = connection.ssl_filter != nullptr
        ? ssl_filter_get_peer_subject(connection.ssl_filter)
        : nullptr;
    const char *peer_issuer_subject = connection.ssl_filter != nullptr
        ? ssl_filter_get_peer_issuer_subject(connection.ssl_filter)
        : nullptr;

    auto &headers = request.headers;
    lb_forward_request_headers(request.pool, headers,
                               request.local_host_and_port,
                               request.remote_host,
                               peer_subject, peer_issuer_subject,
                               cluster_config.mangle_via);

    auto *lease = NewFromPool<StockItemLease>(request.pool, item);

    http_client_request(request.pool,
                        connection.instance.event_loop,
                        tcp_stock_item_get(item),
                        tcp_stock_item_get_domain(item) == AF_LOCAL
                        ? FdType::FD_SOCKET : FdType::FD_TCP,
                        *lease,
                        item.GetStockName(),
                        NULL, NULL,
                        request.method, request.uri,
                        HttpHeaders(std::move(headers)),
                        body.Steal(), true,
                        *this, cancel_ptr);
}

void
LbRequest::OnStockItemError(GError *error)
{
    lb_connection_log_gerror(2, &connection, "Connect error", error);

    body.Clear();

    if (!send_fallback(request, cluster_config.fallback)) {
        const char *msg = connection.listener.verbose_response
            ? error->message
            : "Connection failure";

        http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY,
                                 msg);
    }

    g_error_free(error);
}

/*
 * constructor
 *
 */

inline void
LbRequest::Start()
{
    SocketAddress bind_address = SocketAddress::Null();
    const bool transparent_source = cluster_config.transparent_source;
    if (transparent_source) {
        bind_address = request.remote_address;

        /* reset the port to 0 to allow the kernel to choose one */
        if (bind_address.GetFamily() == AF_INET) {
            struct sockaddr_in *s_in = (struct sockaddr_in *)
                p_memdup(&request.pool, bind_address.GetAddress(),
                         bind_address.GetSize());
            s_in->sin_port = 0;
            bind_address = SocketAddress((const struct sockaddr *)s_in,
                                         bind_address.GetSize());
        } else if (bind_address.GetFamily() == AF_INET6) {
            struct sockaddr_in6 *s_in = (struct sockaddr_in6 *)
                p_memdup(&request.pool, bind_address.GetAddress(),
                         bind_address.GetSize());
            s_in->sin6_port = 0;
            bind_address = SocketAddress((const struct sockaddr *)s_in,
                                         bind_address.GetSize());
        }
    }

    if (cluster_config.HasZeroConf()) {
        /* TODO: generalize the Zeroconf code, implement sticky */

        auto *cluster2 = connection.instance.clusters.Find(cluster_config.name);
        if (cluster2 == nullptr) {
            http_server_send_message(&request,
                                     HTTP_STATUS_INTERNAL_SERVER_ERROR,
                                     "Zeroconf cluster not found");
            return;
        }

        const auto member = cluster2->Pick(GetStickyHash());
        if (member.first == nullptr) {
            http_server_send_message(&request,
                                     HTTP_STATUS_INTERNAL_SERVER_ERROR,
                                     "Zeroconf cluster is empty");
            return;
        }

        assert(member.second.IsDefined());

        tcp_stock_get(*connection.instance.tcp_stock, request.pool,
                      member.first,
                      transparent_source, bind_address,
                      member.second,
                      20,
                      *this, cancel_ptr);

        return;
    }

    tcp_balancer_get(balancer, request.pool,
                     transparent_source,
                     bind_address,
                     GetStickyHash(),
                     cluster_config.address_list,
                     20,
                     *this, cancel_ptr);
}

void
ForwardHttpRequest(LbConnection &connection,
                   HttpServerRequest &request,
                   const LbClusterConfig &cluster_config,
                   CancellablePointer &cancel_ptr)
{
    const auto request2 =
        NewFromPool<LbRequest>(request.pool,
                               connection, cluster_config,
                               *connection.instance.tcp_balancer,
                               request, cancel_ptr);
    request2->Start();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <queue>
#include <vector>
#include <utility>
#include <iostream>
#include <string>
#include <stack>
#include <queue>

using namespace std;

queue<string> lv1;
queue<string> lv2;
queue<string> lv3;
queue<string> lv4;

string temp;
int templv;
int temptime=0;
int usernum;
int users=0;
int read(int now){
	if(now < temptime || users>usernum) return 0;

	do{

		if(temp.empty()){

		}else{

			switch(templv){
				case 1:
					lv1.push(temp);break;
				case 2:
					lv2.push(temp);break;
					case 3:
					lv3.push(temp);break;
					case 4:
					lv4.push(temp);break;
			}
		}
		users++;
		if(users<=usernum){
			temp.resize(21); //需要预先分配空间
			scanf("%d%d%s",&temptime,&templv,&temp[0]);
		}
		else
			return 0;
	}while(temptime<=now);

}
int pop(){
printf("pop");
if(lv4.size()>0){
		printf("%s\n",lv4.front().c_str());
		lv4.pop();
		return 4;
	}

	if(lv3.size()>0){
		printf("%s\n",lv3.front().c_str());
		lv3.pop();
		return 3;
	}

	if(lv2.size()>0){
		printf("%s\n",lv2.front().c_str());
		lv2.pop();
		return 2;
	}

	if(lv1.size()>0){
		printf("%s\n",lv1.front().c_str());
		lv1.pop();
		return 1;
	}
	return 0;
}
int main(int argc, char const *argv[])
{
		int time;
		scanf("%d%d",&usernum,&time);

		for (int i = 0; i <= time && i< usernum *5; ++i)
		{
			read(i);
			//cout<<i<<"\n"<<lv1.size()<<lv2.size()<<lv3.size()<<endl;
			if(i%5==0)
				pop();
		}
		//while(pop()){}
	return 0;
}<commit_msg>update uoj2254<commit_after>#include <stdio.h>
#include <queue>
#include <vector>
#include <utility>
#include <iostream>
#include <string>
#include <stack>
#include <queue>

using namespace std;

queue<string> lv1;
queue<string> lv2;
queue<string> lv3;
queue<string> lv4;

string temp;
int templv;
int temptime=0;
int usernum;
int users=0;
int read(int now){
	if(now < temptime || users>usernum) return 0;

	do{

		if(temp.empty()){

		}else{

			switch(templv){
				case 1:
					lv1.push(temp);break;
				case 2:
					lv2.push(temp);break;
					case 3:
					lv3.push(temp);break;
					case 4:
					lv4.push(temp);break;
			}
		}
		users++;
		if(users<=usernum){
			temp.resize(21); //需要预先分配空间
			scanf("%d%d%s",&temptime,&templv,&temp[0]);
		}
		else
			return 0;
	}while(temptime<=now);

}
int pop(){
printf("pop");
if(lv4.size()>0){
		printf("%s\n",lv4.front().c_str());
		lv4.pop();
		return 4;
	}

	if(lv3.size()>0){
		printf("%s\n",lv3.front().c_str());
		lv3.pop();
		return 3;
	}

	if(lv2.size()>0){
		printf("%s\n",lv2.front().c_str());
		lv2.pop();
		return 2;
	}

	if(lv1.size()>0){
		printf("%s\n",lv1.front().c_str());
		lv1.pop();
		return 1;
	}
	return 0;
}
int main(int argc, char const *argv[])
{
		int time;
		scanf("%d%d",&usernum,&time);

		for (int i = 0; i <= time ; ++i)
		{
			read(i);
			//cout<<i<<"\n"<<lv1.size()<<lv2.size()<<lv3.size()<<endl;
			if(i%5==0)
				pop();
		}
		//while(pop()){}
	return 0;
}<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/util/runtimeexception.h>
#include <fnordmetric/util/uri.h>

namespace fnordmetric {
namespace util {

URI::URI(const std::string& uri_str) : port_(0) {
  parse(uri_str);
}

void URI::parse(const std::string& uri_str) {
  URI::parseURI(
      uri_str,
      &scheme_,
      &userinfo_,
      &host_,
      &port_,
      &path_,
      &query_,
      &fragment_);
}

const std::string& URI::scheme() const {
  return scheme_;
}

const std::string& URI::userinfo() const {
  return userinfo_;
}

const std::string& URI::host() const {
  return host_;
}

const unsigned URI::port() const {
  return port_;
}

const std::string& URI::path() const {
  return path_;
}

const std::string& URI::query() const {
  return query_;
}

const std::vector<std::pair<std::string, std::string>> URI::queryParams()
    const {
  std::vector<std::pair<std::string, std::string>> params;

  if (query_.size() > 0) {
    URI::parseQueryString(query_, &params);
  }

  return params;
}

const std::string& URI::fragment() const {
  return fragment_;
}

std::string URI::toString() const {
  std::string uri_str;

  uri_str.append(scheme());
  uri_str.append(":");

  if (host_.size() > 0) {
    uri_str.append("//");

    if (userinfo_.size() > 0) {
      uri_str.append(userinfo_);
      uri_str.append("@");
    }

    uri_str.append(host_);

    if (port_ > 0) { // FIXPAUL hasPort
      uri_str.append(":");
      uri_str.append(std::to_string(port_));
    }
  }

  uri_str.append(path_);

  if (query_.size() > 0) {
    uri_str.append("?");
    uri_str.append(query_);
  }

  if (fragment_.size() > 0) {
    uri_str.append("#");
    uri_str.append(fragment_);
  }

  return uri_str;
}

void URI::parseURI(
    const std::string& uri_str,
    std::string* scheme,
    std::string* userinfo,
    std::string* host,
    unsigned* port,
    std::string* path,
    std::string* query,
    std::string* fragment) {
  const char* begin = uri_str.c_str();
  const char* end = begin + uri_str.size();

  /* scheme */
  bool has_scheme = false;
  for (const char* cur = begin; cur < end; ++cur) {
    if (cur[0] == ':') {
      *scheme = std::string(begin, cur - begin);
      begin = cur + 1;
      has_scheme = true;
      break;
    }
  }

  if (!has_scheme) {
    RAISE(util::RuntimeException, "invalid URI: must begin with scheme:");
  }

  /* authority */
  if (begin < end - 2 && begin[0] == '/' && begin[1] == '/') {
    begin += 2;
    const char* cur = begin;
    for (; cur < end && *cur != '/' && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      const char* abegin = begin;
      const char* aend = cur;

      /* userinfo */
      for (const char* acur = abegin; acur < aend; ++acur) {
        if (*acur == '/' || *acur == '?' || *acur == '#') {
          break;
        }

        if (*acur == '@') {
          *userinfo = std::string(abegin, acur - abegin);
          abegin = acur + 1;
          break;
        }
      }

      /* host */
      const char* acur = abegin;
      for (; acur < aend &&
            *acur != '/' &&
            *acur != '?' &&
            *acur != '#' &&
            *acur != ':'; ++acur);
      *host = std::string(abegin, acur - abegin);

      /* port */
      if (acur < aend - 1 && *acur == ':') {
        abegin = ++acur;
        for (; *acur >= '0' && *acur <= '9'; ++acur);
        if (acur > abegin) {
          *port = std::stoi(std::string(abegin, acur - abegin));
        }
      }
    }
    begin = cur;
  }

  /* path */
  if (begin < end) {
    const char* cur = begin;
    for (; cur < end && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      *path = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* query */
  if (begin < end && *begin == '?') {
    const char* cur = ++begin;
    for (; cur < end && *cur != '#'; ++cur);
    if (cur > begin) {
      *query = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* fragment */
  if (begin < end - 1 && *begin == '#') {
    *fragment = std::string(begin + 1, end - begin - 1);
  }
}

void URI::parseQueryString(
    const std::string& query,
    std::vector<std::pair<std::string, std::string>>* params) {
  const char* begin = query.c_str();
  const char* end = begin + query.size();

  for (const char* cur = begin; cur < end; ++cur) {
    for (; cur < end && *cur != '=' && *cur != '&'; cur++);
    if (cur > begin && cur < end && *cur == '=' ) {
      std::string key_str(begin, cur - begin);
      const char* val = ++cur;
      for (; cur < end && *cur != '=' && *cur != '&'; cur++);
      if (cur > val) {
        std::string val_str(val, cur - val);
        params->emplace_back(key_str, val_str);
        begin = cur + 1;
      } else {
        break;
      }
    } else {
      break;
    }
  }
}

}
}
<commit_msg>catch all conversion errors<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/util/runtimeexception.h>
#include <fnordmetric/util/uri.h>

namespace fnordmetric {
namespace util {

URI::URI(const std::string& uri_str) : port_(0) {
  parse(uri_str);
}

void URI::parse(const std::string& uri_str) {
  URI::parseURI(
      uri_str,
      &scheme_,
      &userinfo_,
      &host_,
      &port_,
      &path_,
      &query_,
      &fragment_);
}

const std::string& URI::scheme() const {
  return scheme_;
}

const std::string& URI::userinfo() const {
  return userinfo_;
}

const std::string& URI::host() const {
  return host_;
}

const unsigned URI::port() const {
  return port_;
}

const std::string& URI::path() const {
  return path_;
}

const std::string& URI::query() const {
  return query_;
}

const std::vector<std::pair<std::string, std::string>> URI::queryParams()
    const {
  std::vector<std::pair<std::string, std::string>> params;

  if (query_.size() > 0) {
    URI::parseQueryString(query_, &params);
  }

  return params;
}

const std::string& URI::fragment() const {
  return fragment_;
}

std::string URI::toString() const {
  std::string uri_str;

  uri_str.append(scheme());
  uri_str.append(":");

  if (host_.size() > 0) {
    uri_str.append("//");

    if (userinfo_.size() > 0) {
      uri_str.append(userinfo_);
      uri_str.append("@");
    }

    uri_str.append(host_);

    if (port_ > 0) { // FIXPAUL hasPort
      uri_str.append(":");
      uri_str.append(std::to_string(port_));
    }
  }

  uri_str.append(path_);

  if (query_.size() > 0) {
    uri_str.append("?");
    uri_str.append(query_);
  }

  if (fragment_.size() > 0) {
    uri_str.append("#");
    uri_str.append(fragment_);
  }

  return uri_str;
}

void URI::parseURI(
    const std::string& uri_str,
    std::string* scheme,
    std::string* userinfo,
    std::string* host,
    unsigned* port,
    std::string* path,
    std::string* query,
    std::string* fragment) {
  const char* begin = uri_str.c_str();
  const char* end = begin + uri_str.size();

  /* scheme */
  bool has_scheme = false;
  for (const char* cur = begin; cur < end; ++cur) {
    if (cur[0] == ':') {
      *scheme = std::string(begin, cur - begin);
      begin = cur + 1;
      has_scheme = true;
      break;
    }
  }

  if (!has_scheme) {
    RAISE(util::RuntimeException, "invalid URI: must begin with scheme:");
  }

  /* authority */
  if (begin < end - 2 && begin[0] == '/' && begin[1] == '/') {
    begin += 2;
    const char* cur = begin;
    for (; cur < end && *cur != '/' && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      const char* abegin = begin;
      const char* aend = cur;

      /* userinfo */
      for (const char* acur = abegin; acur < aend; ++acur) {
        if (*acur == '/' || *acur == '?' || *acur == '#') {
          break;
        }

        if (*acur == '@') {
          *userinfo = std::string(abegin, acur - abegin);
          abegin = acur + 1;
          break;
        }
      }

      /* host */
      const char* acur = abegin;
      for (; acur < aend &&
            *acur != '/' &&
            *acur != '?' &&
            *acur != '#' &&
            *acur != ':'; ++acur);
      *host = std::string(abegin, acur - abegin);

      /* port */
      if (acur < aend - 1 && *acur == ':') {
        abegin = ++acur;
        for (; *acur >= '0' && *acur <= '9'; ++acur);
        if (acur > abegin) {
          std::string port_str(abegin, acur - abegin);
          try {
            *port = std::stoi(port_str);
          } catch (const std::exception& e) {
            RAISE(
                util::RuntimeException,
                "invalid URI: invalid port: %s",
                port_str.c_str());
          }
        }
      }
    }
    begin = cur;
  }

  /* path */
  if (begin < end) {
    const char* cur = begin;
    for (; cur < end && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      *path = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* query */
  if (begin < end && *begin == '?') {
    const char* cur = ++begin;
    for (; cur < end && *cur != '#'; ++cur);
    if (cur > begin) {
      *query = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* fragment */
  if (begin < end - 1 && *begin == '#') {
    *fragment = std::string(begin + 1, end - begin - 1);
  }
}

void URI::parseQueryString(
    const std::string& query,
    std::vector<std::pair<std::string, std::string>>* params) {
  const char* begin = query.c_str();
  const char* end = begin + query.size();

  for (const char* cur = begin; cur < end; ++cur) {
    for (; cur < end && *cur != '=' && *cur != '&'; cur++);
    if (cur > begin && cur < end && *cur == '=' ) {
      std::string key_str(begin, cur - begin);
      const char* val = ++cur;
      for (; cur < end && *cur != '=' && *cur != '&'; cur++);
      if (cur > val) {
        std::string val_str(val, cur - val);
        params->emplace_back(key_str, val_str);
        begin = cur + 1;
      } else {
        break;
      }
    } else {
      break;
    }
  }
}

}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkRandom.h"

namespace skiagm {

class MovePathGM : public GM {
public:
    MovePathGM() {}

protected:
    SkString onShortName() {
        return SkString("movepath");
    }

    SkISize onISize() { return make_isize(1240, 390); }

    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
                  const SkRect& clip,SkPaint::Cap cap,
                  SkPaint::Style style, SkPath::FillType fill,
                  SkScalar strokeWidth) {
        path.setFillType(fill);
        SkPaint paint;
        paint.setStrokeCap(cap);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(color);
        paint.setStyle(style);
        canvas->save();
        canvas->clipRect(clip);
        canvas->drawPath(path, paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) {
        struct FillAndName {
            SkPath::FillType fFill;
            const char*      fName;
        };
        static const FillAndName gFills[] = {
            {SkPath::kWinding_FillType, "Winding"},
            {SkPath::kEvenOdd_FillType, "Even / Odd"},
            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
        };
        struct StyleAndName {
            SkPaint::Style fStyle;
            const char*    fName;
        };
        static const StyleAndName gStyles[] = {
            {SkPaint::kFill_Style, "Fill"},
            {SkPaint::kStroke_Style, "Stroke"},
            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
        };
        struct CapAndName {
            SkPaint::Cap fCap;
            const char*  fName;
        };
        static const CapAndName gCaps[] = {
            {SkPaint::kButt_Cap, "Butt"},
            {SkPaint::kRound_Cap, "Round"},
            {SkPaint::kSquare_Cap, "Square"},
        };
        struct PathAndName {
            SkPath      fPath;
            const char* fName;
        };
        PathAndName path;
        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
        path.fName = "moveTo";

        SkPaint titlePaint;
        titlePaint.setColor(SK_ColorBLACK);
        titlePaint.setAntiAlias(true);
        titlePaint.setLCDRenderText(true);
        titlePaint.setTextSize(15 * SK_Scalar1);
        const char title[] = "Lone Move Drawn Into Rectangle Clips With "
                             "Indicated Style, Fill and Linecaps, with stroke width 10";
        canvas->drawText(title, strlen(title),
                            20 * SK_Scalar1,
                            20 * SK_Scalar1,
                            titlePaint);

        SkRandom rand;
        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
        canvas->save();
        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
        canvas->save();
        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
            if (0 < cap) {
                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
            }
            canvas->save();
            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
                if (0 < fill) {
                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                }
                canvas->save();
                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                    if (0 < style) {
                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                    }

                    SkColor color = 0xff007000;
                    this->drawPath(path.fPath, canvas, color, rect,
                                    gCaps[cap].fCap, gStyles[style].fStyle,
                                    gFills[fill].fFill, SK_Scalar1*10);

                    SkPaint rectPaint;
                    rectPaint.setColor(SK_ColorBLACK);
                    rectPaint.setStyle(SkPaint::kStroke_Style);
                    rectPaint.setStrokeWidth(-1);
                    rectPaint.setAntiAlias(true);
                    canvas->drawRect(rect, rectPaint);

                    SkPaint labelPaint;
                    labelPaint.setColor(color);
                    labelPaint.setAntiAlias(true);
                    labelPaint.setLCDRenderText(true);
                    labelPaint.setTextSize(10 * SK_Scalar1);
                    canvas->drawText(gStyles[style].fName,
                                        strlen(gStyles[style].fName),
                                        0, rect.height() + 12 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gFills[fill].fName,
                                        strlen(gFills[fill].fName),
                                        0, rect.height() + 24 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gCaps[cap].fName,
                                        strlen(gCaps[cap].fName),
                                        0, rect.height() + 36 * SK_Scalar1,
                                        labelPaint);
                }
                canvas->restore();
            }
            canvas->restore();
        }
        canvas->restore();
        canvas->restore();
    }

private:
    typedef GM INHERITED;
};

class MoveClosePathGM : public GM {
public:
    MoveClosePathGM() {}

protected:
    SkString onShortName() {
        return SkString("moveclosepath");
    }

    SkISize onISize() { return make_isize(1240, 390); }

    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
                  const SkRect& clip,SkPaint::Cap cap,
                  SkPaint::Style style, SkPath::FillType fill,
                  SkScalar strokeWidth) {
        path.setFillType(fill);
        SkPaint paint;
        paint.setStrokeCap(cap);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(color);
        paint.setStyle(style);
        canvas->save();
        canvas->clipRect(clip);
        canvas->drawPath(path, paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) {
        struct FillAndName {
            SkPath::FillType fFill;
            const char*      fName;
        };
        static const FillAndName gFills[] = {
            {SkPath::kWinding_FillType, "Winding"},
            {SkPath::kEvenOdd_FillType, "Even / Odd"},
            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
        };
        struct StyleAndName {
            SkPaint::Style fStyle;
            const char*    fName;
        };
        static const StyleAndName gStyles[] = {
            {SkPaint::kFill_Style, "Fill"},
            {SkPaint::kStroke_Style, "Stroke"},
            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
        };
        struct CapAndName {
            SkPaint::Cap fCap;
            const char*  fName;
        };
        static const CapAndName gCaps[] = {
            {SkPaint::kButt_Cap, "Butt"},
            {SkPaint::kRound_Cap, "Round"},
            {SkPaint::kSquare_Cap, "Square"},
        };
        struct PathAndName {
            SkPath      fPath;
            const char* fName;
        };
        PathAndName path;
        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
        path.fPath.close();
        path.fName = "moveTo-close";

        SkPaint titlePaint;
        titlePaint.setColor(SK_ColorBLACK);
        titlePaint.setAntiAlias(true);
        titlePaint.setLCDRenderText(true);
        titlePaint.setTextSize(15 * SK_Scalar1);
        const char title[] = "Move Close Drawn Into Rectangle Clips With "
                             "Indicated Style, Fill and Linecaps, with stroke width 10";
        canvas->drawText(title, strlen(title),
                            20 * SK_Scalar1,
                            20 * SK_Scalar1,
                            titlePaint);

        SkRandom rand;
        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
        canvas->save();
        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
        canvas->save();
        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
            if (0 < cap) {
                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
            }
            canvas->save();
            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
                if (0 < fill) {
                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                }
                canvas->save();
                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                    if (0 < style) {
                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                    }

                    SkColor color = 0xff007000;
                    this->drawPath(path.fPath, canvas, color, rect,
                                    gCaps[cap].fCap, gStyles[style].fStyle,
                                    gFills[fill].fFill, SK_Scalar1*10);

                    SkPaint rectPaint;
                    rectPaint.setColor(SK_ColorBLACK);
                    rectPaint.setStyle(SkPaint::kStroke_Style);
                    rectPaint.setStrokeWidth(-1);
                    rectPaint.setAntiAlias(true);
                    canvas->drawRect(rect, rectPaint);

                    SkPaint labelPaint;
                    labelPaint.setColor(color);
                    labelPaint.setAntiAlias(true);
                    labelPaint.setLCDRenderText(true);
                    labelPaint.setTextSize(10 * SK_Scalar1);
                    canvas->drawText(gStyles[style].fName,
                                        strlen(gStyles[style].fName),
                                        0, rect.height() + 12 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gFills[fill].fName,
                                        strlen(gFills[fill].fName),
                                        0, rect.height() + 24 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gCaps[cap].fName,
                                        strlen(gCaps[cap].fName),
                                        0, rect.height() + 36 * SK_Scalar1,
                                        labelPaint);
                }
                canvas->restore();
            }
            canvas->restore();
        }
        canvas->restore();
        canvas->restore();
    }

private:
    typedef GM INHERITED;
};

class MoveMovePathGM : public GM {
public:
    MoveMovePathGM() {}

protected:
    SkString onShortName() {
        return SkString("movemovepath");
    }

    SkISize onISize() { return make_isize(1240, 390); }

    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
                  const SkRect& clip,SkPaint::Cap cap,
                  SkPaint::Style style, SkPath::FillType fill,
                  SkScalar strokeWidth) {
        path.setFillType(fill);
        SkPaint paint;
        paint.setStrokeCap(cap);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(color);
        paint.setStyle(style);
        canvas->save();
        canvas->clipRect(clip);
        canvas->drawPath(path, paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) {
        struct FillAndName {
            SkPath::FillType fFill;
            const char*      fName;
        };
        static const FillAndName gFills[] = {
            {SkPath::kWinding_FillType, "Winding"},
            {SkPath::kEvenOdd_FillType, "Even / Odd"},
            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
        };
        struct StyleAndName {
            SkPaint::Style fStyle;
            const char*    fName;
        };
        static const StyleAndName gStyles[] = {
            {SkPaint::kFill_Style, "Fill"},
            {SkPaint::kStroke_Style, "Stroke"},
            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
        };
        struct CapAndName {
            SkPaint::Cap fCap;
            const char*  fName;
        };
        static const CapAndName gCaps[] = {
            {SkPaint::kButt_Cap, "Butt"},
            {SkPaint::kRound_Cap, "Round"},
            {SkPaint::kSquare_Cap, "Square"},
        };
        struct PathAndName {
            SkPath      fPath;
            const char* fName;
        };
        PathAndName path;
        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
        path.fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
        path.fName = "moveTo-moveTo";

        SkPaint titlePaint;
        titlePaint.setColor(SK_ColorBLACK);
        titlePaint.setAntiAlias(true);
        titlePaint.setLCDRenderText(true);
        titlePaint.setTextSize(15 * SK_Scalar1);
        const char title[] = "Move Move Drawn Into Rectangle Clips With "
                             "Indicated Style, Fill and Linecaps, with stroke width 10";
        canvas->drawText(title, strlen(title),
                            20 * SK_Scalar1,
                            20 * SK_Scalar1,
                            titlePaint);

        SkRandom rand;
        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
        canvas->save();
        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
        canvas->save();
        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
            if (0 < cap) {
                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
            }
            canvas->save();
            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
                if (0 < fill) {
                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                }
                canvas->save();
                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                    if (0 < style) {
                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                    }

                    SkColor color = 0xff007000;
                    this->drawPath(path.fPath, canvas, color, rect,
                                    gCaps[cap].fCap, gStyles[style].fStyle,
                                    gFills[fill].fFill, SK_Scalar1*10);

                    SkPaint rectPaint;
                    rectPaint.setColor(SK_ColorBLACK);
                    rectPaint.setStyle(SkPaint::kStroke_Style);
                    rectPaint.setStrokeWidth(-1);
                    rectPaint.setAntiAlias(true);
                    canvas->drawRect(rect, rectPaint);

                    SkPaint labelPaint;
                    labelPaint.setColor(color);
                    labelPaint.setAntiAlias(true);
                    labelPaint.setLCDRenderText(true);
                    labelPaint.setTextSize(10 * SK_Scalar1);
                    canvas->drawText(gStyles[style].fName,
                                        strlen(gStyles[style].fName),
                                        0, rect.height() + 12 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gFills[fill].fName,
                                        strlen(gFills[fill].fName),
                                        0, rect.height() + 24 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gCaps[cap].fName,
                                        strlen(gCaps[cap].fName),
                                        0, rect.height() + 36 * SK_Scalar1,
                                        labelPaint);
                }
                canvas->restore();
            }
            canvas->restore();
        }
        canvas->restore();
        canvas->restore();
    }

private:
    typedef GM INHERITED;
};

class MoveCloseMoveClosePathGM : public GM {
public:
    MoveCloseMoveClosePathGM() {}

protected:
    SkString onShortName() {
        return SkString("moveclosemoveclosepath");
    }

    SkISize onISize() { return make_isize(1240, 390); }

    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
                  const SkRect& clip,SkPaint::Cap cap,
                  SkPaint::Style style, SkPath::FillType fill,
                  SkScalar strokeWidth) {
        path.setFillType(fill);
        SkPaint paint;
        paint.setStrokeCap(cap);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(color);
        paint.setStyle(style);
        canvas->save();
        canvas->clipRect(clip);
        canvas->drawPath(path, paint);
        canvas->restore();
    }

    virtual void onDraw(SkCanvas* canvas) {
        struct FillAndName {
            SkPath::FillType fFill;
            const char*      fName;
        };
        static const FillAndName gFills[] = {
            {SkPath::kWinding_FillType, "Winding"},
            {SkPath::kEvenOdd_FillType, "Even / Odd"},
            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
        };
        struct StyleAndName {
            SkPaint::Style fStyle;
            const char*    fName;
        };
        static const StyleAndName gStyles[] = {
            {SkPaint::kFill_Style, "Fill"},
            {SkPaint::kStroke_Style, "Stroke"},
            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
        };
        struct CapAndName {
            SkPaint::Cap fCap;
            const char*  fName;
        };
        static const CapAndName gCaps[] = {
            {SkPaint::kButt_Cap, "Butt"},
            {SkPaint::kRound_Cap, "Round"},
            {SkPaint::kSquare_Cap, "Square"},
        };
        struct PathAndName {
            SkPath      fPath;
            const char* fName;
        };
        PathAndName path;
        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
        path.fPath.close();
        path.fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
        path.fPath.close();
        path.fName = "moveTo-close-moveTo-close";

        SkPaint titlePaint;
        titlePaint.setColor(SK_ColorBLACK);
        titlePaint.setAntiAlias(true);
        titlePaint.setLCDRenderText(true);
        titlePaint.setTextSize(15 * SK_Scalar1);
        const char title[] = "Move-Close-Move-Close Drawn Into Rectangle Clips With "
                             "Indicated Style, Fill and Linecaps, with stroke width 10";
        canvas->drawText(title, strlen(title),
                            20 * SK_Scalar1,
                            20 * SK_Scalar1,
                            titlePaint);

        SkRandom rand;
        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
        canvas->save();
        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
        canvas->save();
        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
            if (0 < cap) {
                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
            }
            canvas->save();
            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
                if (0 < fill) {
                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                }
                canvas->save();
                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                    if (0 < style) {
                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                    }

                    SkColor color = 0xff007000;
                    this->drawPath(path.fPath, canvas, color, rect,
                                    gCaps[cap].fCap, gStyles[style].fStyle,
                                    gFills[fill].fFill, SK_Scalar1*10);

                    SkPaint rectPaint;
                    rectPaint.setColor(SK_ColorBLACK);
                    rectPaint.setStyle(SkPaint::kStroke_Style);
                    rectPaint.setStrokeWidth(-1);
                    rectPaint.setAntiAlias(true);
                    canvas->drawRect(rect, rectPaint);

                    SkPaint labelPaint;
                    labelPaint.setColor(color);
                    labelPaint.setAntiAlias(true);
                    labelPaint.setLCDRenderText(true);
                    labelPaint.setTextSize(10 * SK_Scalar1);
                    canvas->drawText(gStyles[style].fName,
                                        strlen(gStyles[style].fName),
                                        0, rect.height() + 12 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gFills[fill].fName,
                                        strlen(gFills[fill].fName),
                                        0, rect.height() + 24 * SK_Scalar1,
                                        labelPaint);
                    canvas->drawText(gCaps[cap].fName,
                                        strlen(gCaps[cap].fName),
                                        0, rect.height() + 36 * SK_Scalar1,
                                        labelPaint);
                }
                canvas->restore();
            }
            canvas->restore();
        }
        canvas->restore();
        canvas->restore();
    }

private:
    typedef GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static GM* MPathFactory(void*) { return new MovePathGM; }
static GMRegistry regMPath(MPathFactory);

static GM* MCPathFactory(void*) { return new MoveClosePathGM; }
static GMRegistry regMCPath(MCPathFactory);

static GM* MMPathFactory(void*) { return new MoveMovePathGM; }
static GMRegistry regMMPath(MMPathFactory);

static GM* MCMCPathFactory(void*) { return new MoveCloseMoveClosePathGM; }
static GMRegistry regMCMCPath(MCMCPathFactory);

}
<commit_msg>Removing unnecessary gm tests. Unreviewed but approved by reed@google.com.<commit_after><|endoftext|>


<commit_before>#include "events.h"

#include "hook.h"
#include "callables.h"
#include "../globals.h"
#include "../ipc/ipc_event.h"
#include "../ipc/ipc_server_man.h"
#include "player.h"

#include <arpa/inet.h>

Hook* Events::hPlayerJoinRequest;
Hook* Events::hPlayerSay;
Hook* Events::hPlayerChangeName;
Hook* Events::hServerStatusRequest;

Events::Events() {}
Events::Events(const Events& orig) {}
Events::~Events() {}

void Events::InsertHooks()
{
	Events::hPlayerJoinRequest   = new Hook((void*) Events::locPlayerJoinRequest, 5, (void*) Events::HPlayerJoinRequest);
	Events::hPlayerSay           = new Hook((void*) Events::locPlayerSay, 5, (void*) Events::HPlayerSay);
	Events::hPlayerChangeName    = new Hook((void*) Events::locPlayerNameChange, 5, (void*) Events::HPlayerNameChange);
	Events::hServerStatusRequest = new Hook((void*) Events::locRconStatus, 5, (void*) Events::HServerStatusRequest);
}

/*===============================================================*\
 * EVENTS
\*===============================================================*/

bool Events::HPlayerJoinRequest(unsigned long a1, uint32_t ip, unsigned long a3, unsigned long a4, unsigned long a5)
{
	// Predict slot ID
	unsigned int  slotID       = 0;
	unsigned long slotOffset   = 0x090B4F8C;
	unsigned int  assignedSlot = 0;

	unsigned int maxClients = Callables::GetMaxClients();
	for(uint32_t i = 0x090B4F8C; ;i += 677436)
	{
		if(slotID > maxClients)
			break;

		slotID = 35580271 * ((i - 151736204) >> 2);

		// If the slot's disconnected
		if(*(uint32_t*) i == 0)
		{
			slotOffset = i;

			printf("Slot [%i] is going to be used is currently in state: %i\n", slotID, *(uint32_t*) slotOffset);

			break;
		}

		//bool r = ((Events::funcdefIsPlayerConnectedAtSlot)Events::locfuncIsPlayerConnectedAtSlot)
					//(a1, ip, a3, a4, a5, *(uint32_t *)(i + 32), *(uint32_t *)(i + 36), *(uint32_t *)(i + 40));

		// If the slot was free
		//if(r == false)
			//break;
	}

	// Get the string value out of the IP
	struct in_addr ip_addr;
	ip_addr.s_addr = ip;
	char* addr = inet_ntoa(ip_addr);

	// Copy the IP pointer into a character pointer, this is required because
	// the char* 'addr' is actually a pointer to a space inside the in_addr
	// object, so it will be cleaned once the ip_addr object goes out of scope.
	char* ipAddress = new char[strlen(addr) + 1];
	memcpy(ipAddress, addr, strlen(addr));
	ipAddress[strlen(addr)] = '\0';

	char* cmd = new char[9 + 1];
	strcpy(cmd, "JOINREQ");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) ipAddress, IPCTypes::ch);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	// Execute the origional request to join the server
	Events::hPlayerJoinRequest->UnHook();
	bool rtn = ((Events::funcdefPlayerJoinRequest)Events::locPlayerJoinRequest)(a1, ip, a3, a4, a5);
	Events::hPlayerJoinRequest->Rehook();

	// After the request is executed, we will check if the connection was a success
	// then fire another event.
	Player player(slotID);
	if(player.GetConnState() > 0)
	{
		char* ipAddress = new char[strlen(addr) + 1];
		memcpy(ipAddress, addr, strlen(addr));
		ipAddress[strlen(addr)] = '\0';

		unsigned int playerNameLen = strlen(player.GetName());
		char* playerName = new char[playerNameLen + 1];
		memcpy(playerName, player.GetName(), playerNameLen);
		playerName[playerNameLen] = '\0';

		unsigned int guidLen = strlen(player.GetGuid());
		char* guid = new char[guidLen + 1];
		memcpy(guid, player.GetGuid(), guidLen);
		guid[guidLen] = '\0';

		char* cmd = new char[9 + 1];
		strcpy(cmd, "JOIN");
		IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
		ipcEvent->AddArgument((void*) assignedSlot, IPCTypes::uint);
		ipcEvent->AddArgument((void*) ipAddress, IPCTypes::ch);
		ipcEvent->AddArgument((void*) guid, IPCTypes::ch);
		ipcEvent->AddArgument((void*) playerName, IPCTypes::ch);

		IPCServer::SetEventForBroadcast(ipcEvent);
	}

	return rtn;
}

/**
* Triggered when the player says something
* This function also bypasses the script if !login command is issued on the server
* @param a1 Pointer to the inet object
* @param a2
* @param a3 Sayteam produces 1 and say produces 0
* @param a4 Pointer to the character for message
* @return
*/
int Events::HPlayerSay(unsigned int* playerId, int a2, int teamSay, char* message)
{
	// Prepare the arguments and types for the event
	//int* argTeamSay = new int;
	//*argTeamSay = teamSay;

	Player player(*playerId);
	unsigned int playerNameLen = strlen(player.GetName());
	char* playerName = new char[playerNameLen + 1];
	memcpy(playerName, player.GetName(), playerNameLen);
	playerName[playerNameLen] = '\0';

	unsigned int messageLen = strlen(message);
	char* argMessage = new char[messageLen + 1];
	memcpy(argMessage, message, messageLen);
	argMessage[messageLen] = '\0';

	// Collate the arguments and types
	char* cmd = new char[4 + 1];
	strcpy(cmd, "CHAT");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) *playerId, IPCTypes::uint);
	ipcEvent->AddArgument((void*) playerName, IPCTypes::ch);
	ipcEvent->AddArgument((void*) argMessage, IPCTypes::ch);

	printf("%s: %s\n", playerName, message);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}

int Events::HPlayerNameChange(unsigned int playerOffset)
{
	unsigned int playerId = Callables::GetPlayerIdByOffset(playerOffset);
	char* newNameRtn = Callables::GetValueFromSlashString((char*)(0x0887C320 + 9), "name");

	// Copy the name into a new char
	unsigned int newNameLen = strlen(newNameRtn);
	char* newName = new char[newNameLen + 1];
	memcpy(newName, newNameRtn, newNameLen);
	newName[newNameLen] = '\0';

	char* cmd = new char[10 + 1];
	strcpy(cmd, "CHANGENAME");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) playerId, IPCTypes::uint);
	ipcEvent->AddArgument((void*) newName, IPCTypes::ch);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}

int Events::HServerStatusRequest()
{
	char* cmd = new char[9 + 1];
	strcpy(cmd, "STATUSREQ");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}<commit_msg>Fixed passing of slot ID bug<commit_after>#include "events.h"

#include "hook.h"
#include "callables.h"
#include "../globals.h"
#include "../ipc/ipc_event.h"
#include "../ipc/ipc_server_man.h"
#include "player.h"

#include <arpa/inet.h>

Hook* Events::hPlayerJoinRequest;
Hook* Events::hPlayerSay;
Hook* Events::hPlayerChangeName;
Hook* Events::hServerStatusRequest;

Events::Events() {}
Events::Events(const Events& orig) {}
Events::~Events() {}

void Events::InsertHooks()
{
	Events::hPlayerJoinRequest   = new Hook((void*) Events::locPlayerJoinRequest, 5, (void*) Events::HPlayerJoinRequest);
	Events::hPlayerSay           = new Hook((void*) Events::locPlayerSay, 5, (void*) Events::HPlayerSay);
	Events::hPlayerChangeName    = new Hook((void*) Events::locPlayerNameChange, 5, (void*) Events::HPlayerNameChange);
	Events::hServerStatusRequest = new Hook((void*) Events::locRconStatus, 5, (void*) Events::HServerStatusRequest);
}

/*===============================================================*\
 * EVENTS
\*===============================================================*/

bool Events::HPlayerJoinRequest(unsigned long a1, uint32_t ip, unsigned long a3, unsigned long a4, unsigned long a5)
{
	// Predict slot ID
	unsigned int  slotID       = 0;
	unsigned long slotOffset   = 0x090B4F8C;

	unsigned int maxClients = Callables::GetMaxClients();
	for(uint32_t i = 0x090B4F8C; ;i += 677436)
	{
		if(slotID > maxClients)
			break;

		// If the slot's disconnected
		if(*(uint32_t*) i == 0)
		{
			slotOffset = i;
			slotID = 35580271 * ((i - 151736204) >> 2);
			break;
		}
	}

	printf("Slot %i predicted to connect\n", slotID);

	// Get the string value out of the IP
	struct in_addr ip_addr;
	ip_addr.s_addr = ip;
	char* addr = inet_ntoa(ip_addr);

	// Copy the IP pointer into a character pointer, this is required because
	// the char* 'addr' is actually a pointer to a space inside the in_addr
	// object, so it will be cleaned once the ip_addr object goes out of scope.
	char* ipAddress = new char[strlen(addr) + 1];
	memcpy(ipAddress, addr, strlen(addr));
	ipAddress[strlen(addr)] = '\0';

	char* cmd = new char[9 + 1];
	strcpy(cmd, "JOINREQ");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) ipAddress, IPCTypes::ch);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	// Execute the origional request to join the server
	Events::hPlayerJoinRequest->UnHook();
	bool rtn = ((Events::funcdefPlayerJoinRequest)Events::locPlayerJoinRequest)(a1, ip, a3, a4, a5);
	Events::hPlayerJoinRequest->Rehook();

	// After the request is executed, we will check if the connection was a success
	// then fire another event.
	Player player(slotID);
	if(player.GetConnState() > 0)
	{
		char* ipAddress = new char[strlen(addr) + 1];
		memcpy(ipAddress, addr, strlen(addr));
		ipAddress[strlen(addr)] = '\0';

		unsigned int playerNameLen = strlen(player.GetName());
		char* playerName = new char[playerNameLen + 1];
		memcpy(playerName, player.GetName(), playerNameLen);
		playerName[playerNameLen] = '\0';

		unsigned int guidLen = strlen(player.GetGuid());
		char* guid = new char[guidLen + 1];
		memcpy(guid, player.GetGuid(), guidLen);
		guid[guidLen] = '\0';

		char* cmd = new char[9 + 1];
		strcpy(cmd, "JOIN");
		IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
		ipcEvent->AddArgument((void*) slotID, IPCTypes::uint);
		ipcEvent->AddArgument((void*) ipAddress, IPCTypes::ch);
		ipcEvent->AddArgument((void*) guid, IPCTypes::ch);
		ipcEvent->AddArgument((void*) playerName, IPCTypes::ch);

		IPCServer::SetEventForBroadcast(ipcEvent);
	}

	return rtn;
}

/**
* Triggered when the player says something
* This function also bypasses the script if !login command is issued on the server
* @param a1 Pointer to the inet object
* @param a2
* @param a3 Sayteam produces 1 and say produces 0
* @param a4 Pointer to the character for message
* @return
*/
int Events::HPlayerSay(unsigned int* playerId, int a2, int teamSay, char* message)
{
	// Prepare the arguments and types for the event
	//int* argTeamSay = new int;
	//*argTeamSay = teamSay;

	Player player(*playerId);
	unsigned int playerNameLen = strlen(player.GetName());
	char* playerName = new char[playerNameLen + 1];
	memcpy(playerName, player.GetName(), playerNameLen);
	playerName[playerNameLen] = '\0';

	unsigned int messageLen = strlen(message);
	char* argMessage = new char[messageLen + 1];
	memcpy(argMessage, message, messageLen);
	argMessage[messageLen] = '\0';

	// Collate the arguments and types
	char* cmd = new char[4 + 1];
	strcpy(cmd, "CHAT");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) *playerId, IPCTypes::uint);
	ipcEvent->AddArgument((void*) playerName, IPCTypes::ch);
	ipcEvent->AddArgument((void*) argMessage, IPCTypes::ch);

	printf("%s: %s\n", playerName, message);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}

int Events::HPlayerNameChange(unsigned int playerOffset)
{
	unsigned int playerId = Callables::GetPlayerIdByOffset(playerOffset);
	char* newNameRtn = Callables::GetValueFromSlashString((char*)(0x0887C320 + 9), "name");

	// Copy the name into a new char
	unsigned int newNameLen = strlen(newNameRtn);
	char* newName = new char[newNameLen + 1];
	memcpy(newName, newNameRtn, newNameLen);
	newName[newNameLen] = '\0';

	char* cmd = new char[10 + 1];
	strcpy(cmd, "CHANGENAME");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);
	ipcEvent->AddArgument((void*) playerId, IPCTypes::uint);
	ipcEvent->AddArgument((void*) newName, IPCTypes::ch);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}

int Events::HServerStatusRequest()
{
	char* cmd = new char[9 + 1];
	strcpy(cmd, "STATUSREQ");
	IPCCoD4Event* ipcEvent = new IPCCoD4Event(cmd);

	// Broadcast the event
	IPCServer::SetEventForBroadcast(ipcEvent);

	return 0;
}<|endoftext|>


<commit_before>/*
 * Physically Based Rendering
 * Copyright (c) 2017-2018 Michał Siejak
 */

#include <cstdio>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/Importer.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/LogStream.hpp>

#include "mesh.hpp"

namespace {
	const unsigned int ImportFlags =
		aiProcess_CalcTangentSpace |
		aiProcess_Triangulate |
		aiProcess_SortByPType |
		aiProcess_PreTransformVertices |
		aiProcess_GenNormals |
		aiProcess_GenUVCoords |
		aiProcess_OptimizeMeshes |
		aiProcess_OptimizeGraph |
		aiProcess_Debone |
		aiProcess_ValidateDataStructure;
}

struct LogStream : public Assimp::LogStream
{
	static void initialize()
	{
		if(Assimp::DefaultLogger::isNullLogger()) {
			Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
			Assimp::DefaultLogger::get()->attachStream(new LogStream, Assimp::Logger::Err | Assimp::Logger::Warn);
		}
	}

	void write(const char* message) override
	{
		std::fprintf(stderr, "Assimp: %s", message);
	}
};

Mesh::Mesh(const aiMesh* mesh)
{
	assert(mesh->HasPositions());
	assert(mesh->HasNormals());

	m_vertices.reserve(mesh->mNumVertices);
	for(size_t i=0; i<m_vertices.capacity(); ++i) {
		Vertex vertex;
		vertex.position = {mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z};
		vertex.normal = {mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z};
		if(mesh->HasTangentsAndBitangents()) {
			vertex.tangent = {mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z};
			vertex.bitangent = {mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z};
		}
		if(mesh->HasTextureCoords(0)) {
			vertex.texcoord = {mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y};
		}
		m_vertices.push_back(vertex);
	}

	m_faces.reserve(mesh->mNumFaces);
	for(size_t i=0; i<m_faces.capacity(); ++i) {
		assert(mesh->mFaces[i].mNumIndices == 3);
		m_faces.push_back({mesh->mFaces[i].mIndices[0], mesh->mFaces[i].mIndices[1], mesh->mFaces[i].mIndices[2]});
	}
}

std::shared_ptr<Mesh> Mesh::fromFile(const std::string& filename)
{
	LogStream::initialize();

	std::printf("Loading mesh: %s\n", filename.c_str());

	std::shared_ptr<Mesh> mesh;
	Assimp::Importer importer;

	const aiScene* scene = importer.ReadFile(filename, ImportFlags);
	if(scene && scene->HasMeshes()) {
		mesh = std::shared_ptr<Mesh>(new Mesh{scene->mMeshes[0]});
	}
	else {
		throw std::runtime_error("Failed to load mesh file: " + filename);
	}
	return mesh;
}

std::shared_ptr<Mesh> Mesh::fromString(const std::string& data)
{
	LogStream::initialize();

	std::shared_ptr<Mesh> mesh;
	Assimp::Importer importer;

	const aiScene* scene = importer.ReadFileFromMemory(data.c_str(), data.length(), ImportFlags, "nff");
	if(scene && scene->HasMeshes()) {
		mesh = std::shared_ptr<Mesh>(new Mesh{scene->mMeshes[0]});
	}
	else {
		throw std::runtime_error("Failed to create mesh from string: " + data);
	}
	return mesh;
}
<commit_msg>Removed redundant aiProcess_OptimizeGraph from assimp import flags<commit_after>/*
 * Physically Based Rendering
 * Copyright (c) 2017-2018 Michał Siejak
 */

#include <cstdio>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/Importer.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/LogStream.hpp>

#include "mesh.hpp"

namespace {
	const unsigned int ImportFlags =
		aiProcess_CalcTangentSpace |
		aiProcess_Triangulate |
		aiProcess_SortByPType |
		aiProcess_PreTransformVertices |
		aiProcess_GenNormals |
		aiProcess_GenUVCoords |
		aiProcess_OptimizeMeshes |
		aiProcess_Debone |
		aiProcess_ValidateDataStructure;
}

struct LogStream : public Assimp::LogStream
{
	static void initialize()
	{
		if(Assimp::DefaultLogger::isNullLogger()) {
			Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
			Assimp::DefaultLogger::get()->attachStream(new LogStream, Assimp::Logger::Err | Assimp::Logger::Warn);
		}
	}

	void write(const char* message) override
	{
		std::fprintf(stderr, "Assimp: %s", message);
	}
};

Mesh::Mesh(const aiMesh* mesh)
{
	assert(mesh->HasPositions());
	assert(mesh->HasNormals());

	m_vertices.reserve(mesh->mNumVertices);
	for(size_t i=0; i<m_vertices.capacity(); ++i) {
		Vertex vertex;
		vertex.position = {mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z};
		vertex.normal = {mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z};
		if(mesh->HasTangentsAndBitangents()) {
			vertex.tangent = {mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z};
			vertex.bitangent = {mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z};
		}
		if(mesh->HasTextureCoords(0)) {
			vertex.texcoord = {mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y};
		}
		m_vertices.push_back(vertex);
	}

	m_faces.reserve(mesh->mNumFaces);
	for(size_t i=0; i<m_faces.capacity(); ++i) {
		assert(mesh->mFaces[i].mNumIndices == 3);
		m_faces.push_back({mesh->mFaces[i].mIndices[0], mesh->mFaces[i].mIndices[1], mesh->mFaces[i].mIndices[2]});
	}
}

std::shared_ptr<Mesh> Mesh::fromFile(const std::string& filename)
{
	LogStream::initialize();

	std::printf("Loading mesh: %s\n", filename.c_str());

	std::shared_ptr<Mesh> mesh;
	Assimp::Importer importer;

	const aiScene* scene = importer.ReadFile(filename, ImportFlags);
	if(scene && scene->HasMeshes()) {
		mesh = std::shared_ptr<Mesh>(new Mesh{scene->mMeshes[0]});
	}
	else {
		throw std::runtime_error("Failed to load mesh file: " + filename);
	}
	return mesh;
}

std::shared_ptr<Mesh> Mesh::fromString(const std::string& data)
{
	LogStream::initialize();

	std::shared_ptr<Mesh> mesh;
	Assimp::Importer importer;

	const aiScene* scene = importer.ReadFileFromMemory(data.c_str(), data.length(), ImportFlags, "nff");
	if(scene && scene->HasMeshes()) {
		mesh = std::shared_ptr<Mesh>(new Mesh{scene->mMeshes[0]});
	}
	else {
		throw std::runtime_error("Failed to create mesh from string: " + data);
	}
	return mesh;
}
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <cstddef>

#include <visionaray/math/simd/type_traits.h>
#include <visionaray/math/array.h>
#include <visionaray/math/forward.h>
#include <visionaray/math/vector.h>
#include <visionaray/texture/texture_traits.h>

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// Implement Visionaray's texturing interface for Ptex textures
//

namespace ptex
{

// tex2D
inline vector<4, unorm<8>> tex2D(PtexPtr<PtexTexture> const& tex, coordinate<float> const& coord)
{
    // Older versions of Ptex have only non-const PtexPtr accessors
    PtexPtr<Ptex::PtexTexture>& mutable_tex = const_cast<PtexPtr<PtexTexture>&>(tex);

    if (mutable_tex == nullptr)
    {
        return vector<4, unorm<8>>(1.0f);
    }

    Ptex::PtexFilter::Options opts(Ptex::PtexFilter::FilterType::f_bspline);
    PtexPtr<Ptex::PtexFilter> filter(Ptex::PtexFilter::getFilter(mutable_tex.get(), opts));

    int face_id = coord.face_id >= 0 ? coord.face_id : ~coord.face_id;
    auto face_data = mutable_tex->getData(face_id);
    auto res = face_data->res();

    vec3 rgb;
    filter->eval(
            rgb.data(),
            0,
            mutable_tex->numChannels(),
            face_id,
            coord.u,
            coord.v,
            1.0f / res.u(),
            0.0f,
            0.0f,
            1.0f / res.v()
            );

    return vector<4, unorm<8>>(rgb.x, rgb.y, rgb.z, 1.0f);
}

} // ptex

namespace simd
{

template <
    size_t N,
    typename T = float_from_simd_width<N>
    >
inline ptex::coordinate<T> pack(array<ptex::coordinate<float>, N> const& coords)
{
    ptex::coordinate<T> result;

    int* face_id = reinterpret_cast<int*>(&result.face_id);
    float* u = reinterpret_cast<float*>(&result.u);
    float* v = reinterpret_cast<float*>(&result.v);
    float* du = reinterpret_cast<float*>(&result.du);
    float* dv = reinterpret_cast<float*>(&result.dv);

    for (size_t i = 0; i < N; ++i)
    {
        face_id[i] = coords[i].face_id;
        u[i]       = coords[i].u;
        v[i]       = coords[i].v;
        du[i]      = coords[i].du;
        dv[i]      = coords[i].dv;
    }

    return result;
}

} // simd

// get_tex_coord() non-simd
template <
    typename HR,
    typename T,
    typename = typename std::enable_if<!simd::is_simd_vector<typename HR::scalar_type>::value>::type
    >
inline auto get_tex_coord(
        ptex::face_id_t const*  face_ids,
        HR const&               hr,
        basic_triangle<3, T>    /* */
        )
    -> ptex::coordinate<typename HR::scalar_type>
{
    ptex::coordinate<typename HR::scalar_type> result;

    vec2 tc1(0.0f, 0.0f);
    vec2 tc2(1.0f, 0.0f);
    vec2 tc3(1.0f, 1.0f);
    vec2 tc4(0.0f, 1.0f);

    result.face_id = face_ids[hr.prim_id];

    vec2 uv;

    if (result.face_id >= 0)
    {
        uv = lerp(tc1, tc2, tc3, hr.u, hr.v);
    }
    else
    {
        result.face_id = ~result.face_id;
        uv = lerp(tc1, tc3, tc4, hr.u, hr.v);
    }

    result.u = uv.x;
    result.v = uv.y;

    return result;
}

// get_tex_coord() simd
template <
    typename HR,
    typename T,
    typename = typename std::enable_if<simd::is_simd_vector<typename HR::scalar_type>::value>::type,
    typename = void
    >
inline auto get_tex_coord(
        ptex::face_id_t const*  face_ids,
        HR const&               hr,
        basic_triangle<3, T>    /* */
        )
    -> ptex::coordinate<typename HR::scalar_type>
{
    using U = typename HR::scalar_type;

    auto hrs = unpack(hr);

    array<ptex::coordinate<float>, simd::num_elements<U>::value> coords;

    for (int i = 0; i < simd::num_elements<U>::value; ++i)
    {
        coords[i].face_id = face_ids[hrs[i].prim_id];
        coords[i].u = hrs[i].u;
        coords[i].v = hrs[i].v;
    }

    return simd::pack(coords);
}

template <>
struct texture_dimensions<PtexPtr<PtexTexture>>
{
    enum { value = 2 };
};

} // visionaray
<commit_msg>Revert "Don't forget to flip negative face ids"<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <cstddef>

#include <visionaray/math/simd/type_traits.h>
#include <visionaray/math/array.h>
#include <visionaray/math/forward.h>
#include <visionaray/math/vector.h>
#include <visionaray/texture/texture_traits.h>

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// Implement Visionaray's texturing interface for Ptex textures
//

namespace ptex
{

// tex2D
inline vector<4, unorm<8>> tex2D(PtexPtr<PtexTexture> const& tex, coordinate<float> const& coord)
{
    // Older versions of Ptex have only non-const PtexPtr accessors
    PtexPtr<Ptex::PtexTexture>& mutable_tex = const_cast<PtexPtr<PtexTexture>&>(tex);

    if (mutable_tex == nullptr)
    {
        return vector<4, unorm<8>>(1.0f);
    }

    Ptex::PtexFilter::Options opts(Ptex::PtexFilter::FilterType::f_bspline);
    PtexPtr<Ptex::PtexFilter> filter(Ptex::PtexFilter::getFilter(mutable_tex.get(), opts));

    auto face_data = mutable_tex->getData(coord.face_id);
    auto res = face_data->res();

    vec3 rgb;
    filter->eval(
            rgb.data(),
            0,
            mutable_tex->numChannels(),
            coord.face_id,
            coord.u,
            coord.v,
            1.0f / res.u(),
            0.0f,
            0.0f,
            1.0f / res.v()
            );

    return vector<4, unorm<8>>(rgb.x, rgb.y, rgb.z, 1.0f);
}

} // ptex

namespace simd
{

template <
    size_t N,
    typename T = float_from_simd_width<N>
    >
inline ptex::coordinate<T> pack(array<ptex::coordinate<float>, N> const& coords)
{
    ptex::coordinate<T> result;

    int* face_id = reinterpret_cast<int*>(&result.face_id);
    float* u = reinterpret_cast<float*>(&result.u);
    float* v = reinterpret_cast<float*>(&result.v);
    float* du = reinterpret_cast<float*>(&result.du);
    float* dv = reinterpret_cast<float*>(&result.dv);

    for (size_t i = 0; i < N; ++i)
    {
        face_id[i] = coords[i].face_id;
        u[i]       = coords[i].u;
        v[i]       = coords[i].v;
        du[i]      = coords[i].du;
        dv[i]      = coords[i].dv;
    }

    return result;
}

} // simd

// get_tex_coord() non-simd
template <
    typename HR,
    typename T,
    typename = typename std::enable_if<!simd::is_simd_vector<typename HR::scalar_type>::value>::type
    >
inline auto get_tex_coord(
        ptex::face_id_t const*  face_ids,
        HR const&               hr,
        basic_triangle<3, T>    /* */
        )
    -> ptex::coordinate<typename HR::scalar_type>
{
    ptex::coordinate<typename HR::scalar_type> result;

    vec2 tc1(0.0f, 0.0f);
    vec2 tc2(1.0f, 0.0f);
    vec2 tc3(1.0f, 1.0f);
    vec2 tc4(0.0f, 1.0f);

    result.face_id = face_ids[hr.prim_id];

    vec2 uv;

    if (result.face_id >= 0)
    {
        uv = lerp(tc1, tc2, tc3, hr.u, hr.v);
    }
    else
    {
        result.face_id = ~result.face_id;
        uv = lerp(tc1, tc3, tc4, hr.u, hr.v);
    }

    result.u = uv.x;
    result.v = uv.y;

    return result;
}

// get_tex_coord() simd
template <
    typename HR,
    typename T,
    typename = typename std::enable_if<simd::is_simd_vector<typename HR::scalar_type>::value>::type,
    typename = void
    >
inline auto get_tex_coord(
        ptex::face_id_t const*  face_ids,
        HR const&               hr,
        basic_triangle<3, T>    /* */
        )
    -> ptex::coordinate<typename HR::scalar_type>
{
    using U = typename HR::scalar_type;

    auto hrs = unpack(hr);

    array<ptex::coordinate<float>, simd::num_elements<U>::value> coords;

    for (int i = 0; i < simd::num_elements<U>::value; ++i)
    {
        coords[i].face_id = face_ids[hrs[i].prim_id];
        coords[i].u = hrs[i].u;
        coords[i].v = hrs[i].v;
    }

    return simd::pack(coords);
}

template <>
struct texture_dimensions<PtexPtr<PtexTexture>>
{
    enum { value = 2 };
};

} // visionaray
<|endoftext|>