<commit_before>/*
 * Copyright 2007-2021 CM4all GmbH
 * 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.
 */

#include "Request.hxx"
#include "Instance.hxx"
#include "CsrfProtection.hxx"
#include "Global.hxx"
#include "widget/Widget.hxx"
#include "widget/Ref.hxx"
#include "widget/Class.hxx"
#include "widget/Context.hxx"
#include "widget/LookupHandler.hxx"
#include "widget/Resolver.hxx"
#include "widget/Frame.hxx"
#include "ForwardHeaders.hxx"
#include "http/IncomingRequest.hxx"
#include "http/Headers.hxx"
#include "http/ResponseHandler.hxx"
#include "WidgetLookupProcessor.hxx"
#include "istream/AutoPipeIstream.hxx"
#include "pool/pool.hxx"
#include "io/Logger.hxx"

struct ProxyWidget final : PoolLeakDetector, WidgetLookupHandler, HttpResponseHandler, Cancellable {
	Request &request;

	/**
	 * The view name of the top widget.
	 */
	const char *const view_name;

	/**
	 * The widget currently being processed.
	 */
	Widget *widget;

	/**
	 * A reference to the widget that should be proxied.
	 */
	const WidgetRef *ref;

	const SharedPoolPtr<WidgetContext> ctx;

	CancellablePointer cancel_ptr;

	ProxyWidget(Request &_request, Widget &_widget,
		    const WidgetRef *_ref,
		    SharedPoolPtr<WidgetContext> &&_ctx) noexcept
		:PoolLeakDetector(_request.pool),
		 request(_request),
		 view_name(request.args.Remove("view")),
		 widget(&_widget), ref(_ref), ctx(std::move(_ctx)) {
	}

	void Start(UnusedIstreamPtr body, unsigned options,
		   CancellablePointer &caller_cancel_ptr) noexcept;

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

	void Continue();

	void ResolverCallback() noexcept;

	/* virtual methods from class Cancellable */
	void Cancel() noexcept override;

	/* virtual methods from class WidgetLookupHandler */
	void WidgetFound(Widget &widget) noexcept override;
	void WidgetNotFound() noexcept override;
	void WidgetLookupError(std::exception_ptr ep) noexcept override;

	/* virtual methods from class HttpResponseHandler */
	void OnHttpResponse(http_status_t status, StringMap &&headers,
			    UnusedIstreamPtr body) noexcept override;
	void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * http_response_handler
 *
 */

void
ProxyWidget::OnHttpResponse(http_status_t status, StringMap &&_headers,
			    UnusedIstreamPtr body) noexcept
{
	assert(widget->cls != nullptr);

	/* XXX shall the address view or the transformation view be used
	   to control response header forwarding? */
	const WidgetView *view = widget->GetTransformationView();
	assert(view != nullptr);

	auto headers = request.ForwardResponseHeaders(status, _headers,
						      nullptr, nullptr,
						      view->response_header_forward);

	HttpHeaders headers2(std::move(headers));

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

	if (body)
		body = NewAutoPipeIstream(&request.pool, std::move(body),
					  global_pipe_stock);

	/* disable the following transformations, because they are meant
	   for the template, not for this widget */
	request.CancelTransformations();

	auto &_request = request;
	Destroy();
	_request.DispatchResponse(status, std::move(headers2),
				  std::move(body));
}

void
ProxyWidget::OnHttpError(std::exception_ptr ep) noexcept
{
	widget->DiscardForFocused();

	auto &_request = request;
	Destroy();
	_request.LogDispatchError(ep);
}

/**
 * Is the client allow to select the specified view?
 */
gcc_pure
static bool
widget_view_allowed(Widget &widget, const WidgetView &view)
{
	assert(view.name != nullptr);

	if (widget.from_template.view_name != nullptr &&
	    strcmp(view.name, widget.from_template.view_name) == 0)
		/* always allow when it's the same view that was specified in
		   the template */
		return true;

	/* views with an address must not be selected by the client */
	if (!view.inherited) {
		widget.logger(2,  "view '", view.name,
			      "' is forbidden because it has an address");
		return false;
	}

	/* if the default view is a container, we must await the widget's
	   response to see if we allow the new view; if the response is
	   processable, it may potentially contain widget elements with
	   parameters that must not be exposed to the client */
	if (widget.IsContainerByDefault())
		/* schedule a check in widget_update_view() */
		widget.from_request.unauthorized_view = true;

	return true;
}

inline void
ProxyWidget::Start(UnusedIstreamPtr body, unsigned options,
		   CancellablePointer &caller_cancel_ptr) noexcept
{
	assert(body);
	assert(widget != nullptr);
	assert(ref != nullptr);

	caller_cancel_ptr = *this;

	processor_lookup_widget(request.pool, request.stopwatch,
				std::move(body),
				*widget, ref->id,
				std::move(ctx), options,
				*this, cancel_ptr);
}

void
ProxyWidget::Continue()
{
	assert(!widget->from_request.frame);

	if (!widget->HasDefaultView()) {
		widget->Cancel();
		auto &_request = request;
		Destroy();
		_request.DispatchError(HTTP_STATUS_NOT_FOUND, "No such view");
		return;
	}

	if (ref != nullptr) {
		frame_parent_widget(request.pool, *widget, ref->id, ctx,
				    request.stopwatch,
				    *this, cancel_ptr);
	} else {
		if (widget->cls->require_csrf_token &&
		    MethodNeedsCsrfProtection(widget->from_request.method)) {
			/* pool reference necessary because
			   Request::CheckCsrfToken() may destroy the
			   pool and leave us unable to call our
			   destructor */
			const ScopePoolRef _ref(request.pool);
			if (!request.CheckCsrfToken()) {
				Destroy();
				return;
			}
		}

		if (view_name != nullptr) {
			/* the client can select the view; he can never explicitly
			   select the default view */
			const WidgetView *view = widget->cls->FindViewByName(view_name);
			if (view == nullptr || view->name == nullptr) {
				widget->Cancel();
				auto &_request = request;
				Destroy();
				_request.DispatchError(HTTP_STATUS_NOT_FOUND,
						       "No such view");
				return;
			}

			if (!widget_view_allowed(*widget, *view)) {
				widget->Cancel();
				auto &_request = request;
				Destroy();
				_request.DispatchError(HTTP_STATUS_FORBIDDEN,
						       "Forbidden");
				return;
			}

			widget->from_request.view = view;
		}

		if (widget->cls->direct_addressing &&
		    !request.dissected_uri.path_info.empty())
			/* apply new-style path_info to frame top widget (direct
			   addressing) */
			widget->from_request.path_info =
				p_strndup(&request.pool,
					  request.dissected_uri.path_info.data + 1,
					  request.dissected_uri.path_info.size - 1);

		widget->from_request.frame = true;

		frame_top_widget(request.pool, *widget, ctx,
				 request.stopwatch,
				 *this,
				 cancel_ptr);
	}
}

void
ProxyWidget::ResolverCallback() noexcept
{
	if (widget->cls == nullptr) {
		widget->Cancel();

		char log_msg[256];
		snprintf(log_msg, sizeof(log_msg), "Failed to look up class for widget '%s'",
			 widget->GetLogName());

		auto &_request = request;
		Destroy();
		_request.LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
					  "No such widget type",
					  log_msg);
		return;
	}

	Continue();
}

void
ProxyWidget::WidgetFound(Widget &_widget) noexcept
{
	assert(ref != nullptr);

	widget = &_widget;
	ref = ref->next;

	if (widget->cls == nullptr) {
		ResolveWidget(request.pool, *widget,
			      *request.instance.widget_registry,
			      BIND_THIS_METHOD(ResolverCallback),
			      cancel_ptr);
		return;
	}

	Continue();
}

void
ProxyWidget::WidgetNotFound() noexcept
{
	assert(ref != nullptr);

	widget->Cancel();

	char log_msg[256];
	snprintf(log_msg, sizeof(log_msg), "Widget '%s' not found in %s",
		 ref->id, widget->GetLogName());

	auto &_request = request;
	Destroy();
	_request.LogDispatchError(HTTP_STATUS_NOT_FOUND, "No such widget", log_msg);
}

void
ProxyWidget::WidgetLookupError(std::exception_ptr ep) noexcept
{
	widget->Cancel();
	auto &_request = request;
	Destroy();
	_request.LogDispatchError(ep);
}

/*
 * async operation
 *
 */

void
ProxyWidget::Cancel() noexcept
{
	/* make sure that all widget resources are freed when the request
	   is cancelled */
	widget->Cancel();

	cancel_ptr.Cancel();

	Destroy();
}

/*
 * constructor
 *
 */

void
Request::HandleProxyWidget(UnusedIstreamPtr body,
			   Widget &widget, const WidgetRef *proxy_ref,
			   SharedPoolPtr<WidgetContext> ctx,
			   unsigned options) noexcept
{
	assert(!widget.from_request.frame);
	assert(proxy_ref != nullptr);
	assert(body);

	auto proxy = NewFromPool<ProxyWidget>(pool, *this,
					      widget, proxy_ref,
					      std::move(ctx));
	proxy->Start(std::move(body), options, cancel_ptr);
}
<commit_msg>bp/ProxyWidget: convert to class<commit_after>/*
 * Copyright 2007-2021 CM4all GmbH
 * 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.
 */

#include "Request.hxx"
#include "Instance.hxx"
#include "CsrfProtection.hxx"
#include "Global.hxx"
#include "widget/Widget.hxx"
#include "widget/Ref.hxx"
#include "widget/Class.hxx"
#include "widget/Context.hxx"
#include "widget/LookupHandler.hxx"
#include "widget/Resolver.hxx"
#include "widget/Frame.hxx"
#include "ForwardHeaders.hxx"
#include "http/IncomingRequest.hxx"
#include "http/Headers.hxx"
#include "http/ResponseHandler.hxx"
#include "WidgetLookupProcessor.hxx"
#include "istream/AutoPipeIstream.hxx"
#include "pool/pool.hxx"
#include "io/Logger.hxx"

class ProxyWidget final : PoolLeakDetector, WidgetLookupHandler, HttpResponseHandler, Cancellable {
	Request &request;

	/**
	 * The view name of the top widget.
	 */
	const char *const view_name;

	/**
	 * The widget currently being processed.
	 */
	Widget *widget;

	/**
	 * A reference to the widget that should be proxied.
	 */
	const WidgetRef *ref;

	const SharedPoolPtr<WidgetContext> ctx;

	CancellablePointer cancel_ptr;

public:
	ProxyWidget(Request &_request, Widget &_widget,
		    const WidgetRef *_ref,
		    SharedPoolPtr<WidgetContext> &&_ctx) noexcept
		:PoolLeakDetector(_request.pool),
		 request(_request),
		 view_name(request.args.Remove("view")),
		 widget(&_widget), ref(_ref), ctx(std::move(_ctx)) {
	}

	void Start(UnusedIstreamPtr body, unsigned options,
		   CancellablePointer &caller_cancel_ptr) noexcept;

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

	void Continue();

	void ResolverCallback() noexcept;

	/* virtual methods from class Cancellable */
	void Cancel() noexcept override;

	/* virtual methods from class WidgetLookupHandler */
	void WidgetFound(Widget &widget) noexcept override;
	void WidgetNotFound() noexcept override;
	void WidgetLookupError(std::exception_ptr ep) noexcept override;

	/* virtual methods from class HttpResponseHandler */
	void OnHttpResponse(http_status_t status, StringMap &&headers,
			    UnusedIstreamPtr body) noexcept override;
	void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * http_response_handler
 *
 */

void
ProxyWidget::OnHttpResponse(http_status_t status, StringMap &&_headers,
			    UnusedIstreamPtr body) noexcept
{
	assert(widget->cls != nullptr);

	/* XXX shall the address view or the transformation view be used
	   to control response header forwarding? */
	const WidgetView *view = widget->GetTransformationView();
	assert(view != nullptr);

	auto headers = request.ForwardResponseHeaders(status, _headers,
						      nullptr, nullptr,
						      view->response_header_forward);

	HttpHeaders headers2(std::move(headers));

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

	if (body)
		body = NewAutoPipeIstream(&request.pool, std::move(body),
					  global_pipe_stock);

	/* disable the following transformations, because they are meant
	   for the template, not for this widget */
	request.CancelTransformations();

	auto &_request = request;
	Destroy();
	_request.DispatchResponse(status, std::move(headers2),
				  std::move(body));
}

void
ProxyWidget::OnHttpError(std::exception_ptr ep) noexcept
{
	widget->DiscardForFocused();

	auto &_request = request;
	Destroy();
	_request.LogDispatchError(ep);
}

/**
 * Is the client allow to select the specified view?
 */
gcc_pure
static bool
widget_view_allowed(Widget &widget, const WidgetView &view)
{
	assert(view.name != nullptr);

	if (widget.from_template.view_name != nullptr &&
	    strcmp(view.name, widget.from_template.view_name) == 0)
		/* always allow when it's the same view that was specified in
		   the template */
		return true;

	/* views with an address must not be selected by the client */
	if (!view.inherited) {
		widget.logger(2,  "view '", view.name,
			      "' is forbidden because it has an address");
		return false;
	}

	/* if the default view is a container, we must await the widget's
	   response to see if we allow the new view; if the response is
	   processable, it may potentially contain widget elements with
	   parameters that must not be exposed to the client */
	if (widget.IsContainerByDefault())
		/* schedule a check in widget_update_view() */
		widget.from_request.unauthorized_view = true;

	return true;
}

inline void
ProxyWidget::Start(UnusedIstreamPtr body, unsigned options,
		   CancellablePointer &caller_cancel_ptr) noexcept
{
	assert(body);
	assert(widget != nullptr);
	assert(ref != nullptr);

	caller_cancel_ptr = *this;

	processor_lookup_widget(request.pool, request.stopwatch,
				std::move(body),
				*widget, ref->id,
				std::move(ctx), options,
				*this, cancel_ptr);
}

void
ProxyWidget::Continue()
{
	assert(!widget->from_request.frame);

	if (!widget->HasDefaultView()) {
		widget->Cancel();
		auto &_request = request;
		Destroy();
		_request.DispatchError(HTTP_STATUS_NOT_FOUND, "No such view");
		return;
	}

	if (ref != nullptr) {
		frame_parent_widget(request.pool, *widget, ref->id, ctx,
				    request.stopwatch,
				    *this, cancel_ptr);
	} else {
		if (widget->cls->require_csrf_token &&
		    MethodNeedsCsrfProtection(widget->from_request.method)) {
			/* pool reference necessary because
			   Request::CheckCsrfToken() may destroy the
			   pool and leave us unable to call our
			   destructor */
			const ScopePoolRef _ref(request.pool);
			if (!request.CheckCsrfToken()) {
				Destroy();
				return;
			}
		}

		if (view_name != nullptr) {
			/* the client can select the view; he can never explicitly
			   select the default view */
			const WidgetView *view = widget->cls->FindViewByName(view_name);
			if (view == nullptr || view->name == nullptr) {
				widget->Cancel();
				auto &_request = request;
				Destroy();
				_request.DispatchError(HTTP_STATUS_NOT_FOUND,
						       "No such view");
				return;
			}

			if (!widget_view_allowed(*widget, *view)) {
				widget->Cancel();
				auto &_request = request;
				Destroy();
				_request.DispatchError(HTTP_STATUS_FORBIDDEN,
						       "Forbidden");
				return;
			}

			widget->from_request.view = view;
		}

		if (widget->cls->direct_addressing &&
		    !request.dissected_uri.path_info.empty())
			/* apply new-style path_info to frame top widget (direct
			   addressing) */
			widget->from_request.path_info =
				p_strndup(&request.pool,
					  request.dissected_uri.path_info.data + 1,
					  request.dissected_uri.path_info.size - 1);

		widget->from_request.frame = true;

		frame_top_widget(request.pool, *widget, ctx,
				 request.stopwatch,
				 *this,
				 cancel_ptr);
	}
}

void
ProxyWidget::ResolverCallback() noexcept
{
	if (widget->cls == nullptr) {
		widget->Cancel();

		char log_msg[256];
		snprintf(log_msg, sizeof(log_msg), "Failed to look up class for widget '%s'",
			 widget->GetLogName());

		auto &_request = request;
		Destroy();
		_request.LogDispatchError(HTTP_STATUS_BAD_GATEWAY,
					  "No such widget type",
					  log_msg);
		return;
	}

	Continue();
}

void
ProxyWidget::WidgetFound(Widget &_widget) noexcept
{
	assert(ref != nullptr);

	widget = &_widget;
	ref = ref->next;

	if (widget->cls == nullptr) {
		ResolveWidget(request.pool, *widget,
			      *request.instance.widget_registry,
			      BIND_THIS_METHOD(ResolverCallback),
			      cancel_ptr);
		return;
	}

	Continue();
}

void
ProxyWidget::WidgetNotFound() noexcept
{
	assert(ref != nullptr);

	widget->Cancel();

	char log_msg[256];
	snprintf(log_msg, sizeof(log_msg), "Widget '%s' not found in %s",
		 ref->id, widget->GetLogName());

	auto &_request = request;
	Destroy();
	_request.LogDispatchError(HTTP_STATUS_NOT_FOUND, "No such widget", log_msg);
}

void
ProxyWidget::WidgetLookupError(std::exception_ptr ep) noexcept
{
	widget->Cancel();
	auto &_request = request;
	Destroy();
	_request.LogDispatchError(ep);
}

/*
 * async operation
 *
 */

void
ProxyWidget::Cancel() noexcept
{
	/* make sure that all widget resources are freed when the request
	   is cancelled */
	widget->Cancel();

	cancel_ptr.Cancel();

	Destroy();
}

/*
 * constructor
 *
 */

void
Request::HandleProxyWidget(UnusedIstreamPtr body,
			   Widget &widget, const WidgetRef *proxy_ref,
			   SharedPoolPtr<WidgetContext> ctx,
			   unsigned options) noexcept
{
	assert(!widget.from_request.frame);
	assert(proxy_ref != nullptr);
	assert(body);

	auto proxy = NewFromPool<ProxyWidget>(pool, *this,
					      widget, proxy_ref,
					      std::move(ctx));
	proxy->Start(std::move(body), options, cancel_ptr);
}
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (stoi(tok)) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<commit_msg>Update expression-evaluation.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(const vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (atoi(tok.c_str())) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<|endoftext|>


<commit_before><commit_msg>Verified string count against new string<commit_after><|endoftext|>


<commit_before><commit_msg>+ ports: everybody but Karsten loves Jan<commit_after><|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2020 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "recent_files.h"

#include "str_helpers.h"
#include "unicode_helpers.h"
#include "utility.h"

#ifdef __WXOSX__
#import <AppKit/NSDocumentController.h>
#endif

#include <wx/config.h>
#include <wx/filehistory.h>
#include <wx/filename.h>
#include <wx/log.h>
#include <wx/menu.h>
#include <wx/weakref.h>
#include <wx/xrc/xmlres.h>

#include <mutex>
#include <map>
#include <set>
#include <vector>

wxDEFINE_EVENT(EVT_OPEN_RECENT_FILE, wxCommandEvent);

namespace
{

// Track lifetime of menus, removes no longer existing menus automatically
template<typename Payload>
class menus_tracker
{
public:
    void add(wxMenuItem *menuItem, Payload *payload)
    {
        cleanup_destroyed();
        m_menus[menuItem->GetMenu()] = payload;
    }

    template<typename Fn>
    Payload* find_if(Fn&& predicate)
    {
        cleanup_destroyed();
        for (auto& m: m_menus)
        {
            if (predicate(m.first))
                return m.second;
        }
        return nullptr;
    }

    template<typename Fn>
    void for_all(Fn&& func)
    {
        cleanup_destroyed();
        for (auto& m: m_menus)
            func(m.second);
    }

    virtual ~menus_tracker() {}

protected:
    void cleanup_destroyed()
    {
        auto i = m_menus.begin();
        while (i != m_menus.end())
        {
            if (i->first)
                ++i;
            else
                i = m_menus.erase(i);
        }
    }

    std::map<wxWeakRef<wxMenu>, Payload*> m_menus;
};

} // anonymous namespace

#ifdef __WXOSX__

// Implementation for macOS uses native recent documents functionality with native UI.
// Some gross hacks are however required to make it work with wx's menubar and mostly
// with the way wx handles switching per-window menus on macOS where only one per-app
// menu exists.
class RecentFiles::impl
{
public:
    impl() {}

    void UseMenu(wxMenuItem *menuItem)
    {
        NSMenu *native = menuItem->GetMenu()->GetHMenu();
        NSMenuItem *nativeItem = [native itemWithTitle:str::to_NS(menuItem->GetItemLabelText())];
        wxCHECK_RET( nativeItem, "couldn't find NSMenuItem for a menu item" );
        m_menus.add(menuItem, nativeItem);
    }

    void NoteRecentFile(wxFileName fn)
    {
        fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE);
        NSURL *url = [NSURL fileURLWithPath:str::to_NS(fn.GetFullPath())];
        [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:url];
    }

    void MacCreateFakeOpenRecentMenu()
    {
        // Populate the menu with a hack that will be replaced.
        NSMenu *mainMenu = [NSApp mainMenu];

        NSMenuItem *item = [mainMenu addItemWithTitle:@"File" action:NULL keyEquivalent:@""];
        NSMenu *menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"File", nil)];

        item = [menu addItemWithTitle:NSLocalizedString(@"Open Recent", nil)
                action:NULL
                keyEquivalent:@""];
        NSMenu *openRecentMenu = [[NSMenu alloc] initWithTitle:@"Open Recent"];
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wundeclared-selector"
        [openRecentMenu performSelector:@selector(_setMenuName:) withObject:@"NSRecentDocumentsMenu"];
        #pragma clang diagnostic pop
        [menu setSubmenu:openRecentMenu forItem:item];
        m_recentMenuItem = item;
        m_recentMenu = openRecentMenu;

        item = [openRecentMenu addItemWithTitle:NSLocalizedString(@"Clear Menu", nil)
                action:@selector(clearRecentDocuments:)
                keyEquivalent:@""];
    }

    void MacTransferMenuTo(wxMenuBar *bar)
    {
        if (m_recentMenuItem)
            [m_recentMenuItem setSubmenu:nil];

        if (!bar)
            return;

        NSMenuItem *nativeItem = m_menus.find_if([=](wxMenu *menu){ return menu->GetMenuBar() == bar; });
        if (nativeItem)
        {
            [nativeItem setSubmenu:m_recentMenu];
            m_recentMenuItem = nativeItem;
        }
    }

private:
    menus_tracker<NSMenuItem> m_menus;
    NSMenu *m_recentMenu = nullptr;
    NSMenuItem *m_recentMenuItem = nullptr;
};

#else // !__WXOSX__

// Generic implementation use wxFileHistory (mainly for Windows). Doesn't use
// wxFileHistory's menus management, because it requires explicit RemoveMenu()
// and because we want to add "Clear menu" items as well.
class RecentFiles::impl
{
public:
    impl()
    {
        wxConfigBase *cfg = wxConfig::Get();
        cfg->SetPath("/");
        m_history.Load(*cfg);
    }

    void UseMenu(wxMenuItem *menuItem)
    {
        auto menu = menuItem->GetSubMenu();
        m_menus.add(menuItem, menu);

        RebuildMenu(menu);

        menu->Bind(wxEVT_MENU, [=](wxCommandEvent& e)
        {
            wxString f(m_history.GetHistoryFile(e.GetId() - wxID_FILE1));
            if (!wxFileExists(f))
            {
                wxLogError(_(L"File “%s” doesn’t exist."), f.c_str());
                return;
            }

            wxCommandEvent event(EVT_OPEN_RECENT_FILE);
            event.SetEventObject(menu);
            event.SetString(f);
            menu->GetWindow()->ProcessWindowEvent(event);
        },
        wxID_FILE1, wxID_FILE9);

        menu->Bind(wxEVT_MENU, [=](wxCommandEvent&)
        {
            ClearHistory();
        },
        m_idClear);
    }

    void NoteRecentFile(wxFileName fn)
    {
        fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE);
        m_history.AddFileToHistory(fn.GetFullPath());

        UpdateAfterChange();
    }

    void ClearHistory()
    {
        while (m_history.GetCount())
            m_history.RemoveFileFromHistory(0);

        UpdateAfterChange();
    }

protected:
    void RebuildMenu(wxMenu *menu)
    {
        // clear the menu entirely:
        while (menu->GetMenuItemCount())
            menu->Destroy(menu->FindItemByPosition(0));

        // add wxFileHistory files:
        m_history.AddFilesToMenu(menu);

        // and an item for clearning the menu:
        const bool hasItems = menu->GetMenuItemCount() > 0;
        if (hasItems)
            menu->AppendSeparator();
        auto clearItem = menu->Append(m_idClear, MSW_OR_OTHER(_("Clear menu"), _("Clear Menu")));
        clearItem->Enable(hasItems);

    }

    void UpdateAfterChange()
    {
        // Update all menus with visible history:
        m_menus.for_all([=](wxMenu *menu){ RebuildMenu(menu); });

        // Save the changes to persistent storage:
        wxConfigBase *cfg = wxConfig::Get();
        cfg->SetPath("/");
        m_history.Save(*cfg);
    }

    // customized implementation of storage that makes nicer menus
    class MyHistory : public wxFileHistory
    {
    public:
        void AddFilesToMenu(wxMenu *menu) override
        {
            std::vector<wxFileName> files;
            files.reserve(m_fileHistory.size());
            for (auto& f : m_fileHistory)
                files.emplace_back(f);

            std::map<wxString, int> nameUses;
            for (auto& f : files)
            {
                auto name = f.GetFullName();
                nameUses[name] += 1;
            }

            for (size_t i = 0; i < files.size(); ++i)
                DoAddFile(menu, i, files[i], nameUses[files[i].GetFullName()] > 1);
        }

    protected:
        void DoAddFile(wxMenu* menu, int n, const wxFileName& fn, bool showFullPath)
        {
            auto menuEntry = bidi::platform_mark_direction(
                                 showFullPath
                                 ? wxString::Format(L"%s — %s", fn.GetFullName(), fn.GetPath())
                                 : fn.GetFullName());

            // we need to quote '&' characters which are used for mnemonics
            menuEntry.Replace("&", "&&");

            auto item = menu->Append(wxID_FILE1 + n, wxString::Format("&%d %s", n + 1, menuEntry));
            item->SetHelp(fn.GetFullPath());
        }

        file_icons m_icons;
    };

private:
    const wxWindowID m_idClear = wxNewId();
    MyHistory m_history;
    menus_tracker<wxMenu> m_menus;
};

#endif // !__WXOSX__

// Boilerplate:

namespace
{
    static std::once_flag initializationFlag;
    RecentFiles* gs_instance = nullptr;
}

RecentFiles& RecentFiles::Get()
{
    std::call_once(initializationFlag, []() {
        gs_instance = new RecentFiles;
    });
    return *gs_instance;
}

void RecentFiles::CleanUp()
{
    if (gs_instance)
    {
        delete gs_instance;
        gs_instance = nullptr;
    }
}

RecentFiles::RecentFiles() : m_impl(new impl) {}
RecentFiles::~RecentFiles() {}

void RecentFiles::UseMenu(wxMenuItem *menu)
{
    m_impl->UseMenu(menu);
}

void RecentFiles::NoteRecentFile(const wxFileName& fn)
{
    m_impl->NoteRecentFile(fn);
}

#ifdef __WXOSX__
void RecentFiles::MacCreateFakeOpenRecentMenu()
{
    m_impl->MacCreateFakeOpenRecentMenu();
}

void RecentFiles::MacTransferMenuTo(wxMenuBar *bar)
{
    m_impl->MacTransferMenuTo(bar);
}
#endif // __WXOSX__
<commit_msg>Add recent files icons on Windows<commit_after>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2020 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "recent_files.h"

#include "hidpi.h"
#include "str_helpers.h"
#include "unicode_helpers.h"
#include "utility.h"

#ifdef __WXOSX__
#import <AppKit/NSDocumentController.h>
#endif

#include <wx/config.h>
#include <wx/filehistory.h>
#include <wx/filename.h>
#include <wx/log.h>
#include <wx/menu.h>
#include <wx/mimetype.h>
#include <wx/settings.h>
#include <wx/weakref.h>
#include <wx/xrc/xmlres.h>

#include <memory>
#include <mutex>
#include <map>
#include <set>
#include <vector>

wxDEFINE_EVENT(EVT_OPEN_RECENT_FILE, wxCommandEvent);

namespace
{

// Track lifetime of menus, removes no longer existing menus automatically
template<typename Payload>
class menus_tracker
{
public:
    void add(wxMenuItem *menuItem, Payload *payload)
    {
        cleanup_destroyed();
        m_menus[menuItem->GetMenu()] = payload;
    }

    template<typename Fn>
    Payload* find_if(Fn&& predicate)
    {
        cleanup_destroyed();
        for (auto& m: m_menus)
        {
            if (predicate(m.first))
                return m.second;
        }
        return nullptr;
    }

    template<typename Fn>
    void for_all(Fn&& func)
    {
        cleanup_destroyed();
        for (auto& m: m_menus)
            func(m.second);
    }

    virtual ~menus_tracker() {}

protected:
    void cleanup_destroyed()
    {
        auto i = m_menus.begin();
        while (i != m_menus.end())
        {
            if (i->first)
                ++i;
            else
                i = m_menus.erase(i);
        }
    }

    std::map<wxWeakRef<wxMenu>, Payload*> m_menus;
};

#ifndef __WXOSX__
class file_icons
{
public:
    file_icons() {}

    wxBitmap get(const wxString& ext)
    {
        auto i = m_cache.find(ext);
        if (i != m_cache.end())
            return i->second;

        std::unique_ptr<wxFileType> ft(wxTheMimeTypesManager->GetFileTypeFromExtension(ext));
        if (ft)
        {
            wxIconLocation icon;
            if (ft->GetIcon(&icon))
                return m_cache.emplace(ext, create_bitmap(icon)).first->second;
        }

        m_cache.emplace(ext, wxNullBitmap);
        return wxNullBitmap;
    }

private:
    wxBitmap create_bitmap(const wxIconLocation& loc)
    {
        const int size = wxSystemSettings::GetMetric(wxSYS_SMALLICON_X);
        wxString fullname = loc.GetFileName();
#ifdef __WXMSW__
        if (loc.GetIndex())
        {
            // wxICOFileHandler accepts names in the format "filename;index"
            fullname << ';' << loc.GetIndex();
        }
#endif
        wxIcon icon(fullname, wxBITMAP_TYPE_ICO, size, size);
        if (!icon.IsOk())
            icon.LoadFile(fullname, wxBITMAP_TYPE_ICO);

        return icon;
    }

    std::map<wxString, wxBitmap> m_cache;
};
#endif // !__WXOSX__

} // anonymous namespace

#ifdef __WXOSX__

// Implementation for macOS uses native recent documents functionality with native UI.
// Some gross hacks are however required to make it work with wx's menubar and mostly
// with the way wx handles switching per-window menus on macOS where only one per-app
// menu exists.
class RecentFiles::impl
{
public:
    impl() {}

    void UseMenu(wxMenuItem *menuItem)
    {
        NSMenu *native = menuItem->GetMenu()->GetHMenu();
        NSMenuItem *nativeItem = [native itemWithTitle:str::to_NS(menuItem->GetItemLabelText())];
        wxCHECK_RET( nativeItem, "couldn't find NSMenuItem for a menu item" );
        m_menus.add(menuItem, nativeItem);
    }

    void NoteRecentFile(wxFileName fn)
    {
        fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE);
        NSURL *url = [NSURL fileURLWithPath:str::to_NS(fn.GetFullPath())];
        [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:url];
    }

    void MacCreateFakeOpenRecentMenu()
    {
        // Populate the menu with a hack that will be replaced.
        NSMenu *mainMenu = [NSApp mainMenu];

        NSMenuItem *item = [mainMenu addItemWithTitle:@"File" action:NULL keyEquivalent:@""];
        NSMenu *menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"File", nil)];

        item = [menu addItemWithTitle:NSLocalizedString(@"Open Recent", nil)
                action:NULL
                keyEquivalent:@""];
        NSMenu *openRecentMenu = [[NSMenu alloc] initWithTitle:@"Open Recent"];
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wundeclared-selector"
        [openRecentMenu performSelector:@selector(_setMenuName:) withObject:@"NSRecentDocumentsMenu"];
        #pragma clang diagnostic pop
        [menu setSubmenu:openRecentMenu forItem:item];
        m_recentMenuItem = item;
        m_recentMenu = openRecentMenu;

        item = [openRecentMenu addItemWithTitle:NSLocalizedString(@"Clear Menu", nil)
                action:@selector(clearRecentDocuments:)
                keyEquivalent:@""];
    }

    void MacTransferMenuTo(wxMenuBar *bar)
    {
        if (m_recentMenuItem)
            [m_recentMenuItem setSubmenu:nil];

        if (!bar)
            return;

        NSMenuItem *nativeItem = m_menus.find_if([=](wxMenu *menu){ return menu->GetMenuBar() == bar; });
        if (nativeItem)
        {
            [nativeItem setSubmenu:m_recentMenu];
            m_recentMenuItem = nativeItem;
        }
    }

private:
    menus_tracker<NSMenuItem> m_menus;
    NSMenu *m_recentMenu = nullptr;
    NSMenuItem *m_recentMenuItem = nullptr;
};

#else // !__WXOSX__

// Generic implementation use wxFileHistory (mainly for Windows). Doesn't use
// wxFileHistory's menus management, because it requires explicit RemoveMenu()
// and because we want to add "Clear menu" items as well.
class RecentFiles::impl
{
public:
    impl()
    {
        wxConfigBase *cfg = wxConfig::Get();
        cfg->SetPath("/");
        m_history.Load(*cfg);
    }

    void UseMenu(wxMenuItem *menuItem)
    {
        auto menu = menuItem->GetSubMenu();
        m_menus.add(menuItem, menu);

        RebuildMenu(menu);

        menu->Bind(wxEVT_MENU, [=](wxCommandEvent& e)
        {
            wxString f(m_history.GetHistoryFile(e.GetId() - wxID_FILE1));
            if (!wxFileExists(f))
            {
                wxLogError(_(L"File “%s” doesn’t exist."), f.c_str());
                return;
            }

            wxCommandEvent event(EVT_OPEN_RECENT_FILE);
            event.SetEventObject(menu);
            event.SetString(f);
            menu->GetWindow()->ProcessWindowEvent(event);
        },
        wxID_FILE1, wxID_FILE9);

        menu->Bind(wxEVT_MENU, [=](wxCommandEvent&)
        {
            ClearHistory();
        },
        m_idClear);
    }

    void NoteRecentFile(wxFileName fn)
    {
        fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE);
        m_history.AddFileToHistory(fn.GetFullPath());

        UpdateAfterChange();
    }

    void ClearHistory()
    {
        while (m_history.GetCount())
            m_history.RemoveFileFromHistory(0);

        UpdateAfterChange();
    }

protected:
    void RebuildMenu(wxMenu *menu)
    {
        // clear the menu entirely:
        while (menu->GetMenuItemCount())
            menu->Destroy(menu->FindItemByPosition(0));

        // add wxFileHistory files:
        m_history.AddFilesToMenu(menu);

        // and an item for clearning the menu:
        const bool hasItems = menu->GetMenuItemCount() > 0;
        if (hasItems)
            menu->AppendSeparator();
        auto clearItem = menu->Append(m_idClear, MSW_OR_OTHER(_("Clear menu"), _("Clear Menu")));
        clearItem->Enable(hasItems);

    }

    void UpdateAfterChange()
    {
        // Update all menus with visible history:
        m_menus.for_all([=](wxMenu *menu){ RebuildMenu(menu); });

        // Save the changes to persistent storage:
        wxConfigBase *cfg = wxConfig::Get();
        cfg->SetPath("/");
        m_history.Save(*cfg);
    }

    // customized implementation of storage that makes nicer menus
    class MyHistory : public wxFileHistory
    {
    public:
        void AddFilesToMenu(wxMenu *menu) override
        {
            std::vector<wxFileName> files;
            files.reserve(m_fileHistory.size());
            for (auto& f : m_fileHistory)
                files.emplace_back(f);

            std::map<wxString, int> nameUses;
            for (auto& f : files)
            {
                auto name = f.GetFullName();
                nameUses[name] += 1;
            }

            for (size_t i = 0; i < files.size(); ++i)
                DoAddFile(menu, i, files[i], nameUses[files[i].GetFullName()] > 1);
        }

    protected:
        void DoAddFile(wxMenu* menu, int n, const wxFileName& fn, bool showFullPath)
        {
            auto menuEntry = bidi::platform_mark_direction(
                                 showFullPath
                                 ? wxString::Format(L"%s — %s", fn.GetFullName(), fn.GetPath())
                                 : fn.GetFullName());

            // we need to quote '&' characters which are used for mnemonics
            menuEntry.Replace("&", "&&");

            auto item = menu->Append(wxID_FILE1 + n, wxString::Format("&%d %s", n + 1, menuEntry));
            item->SetHelp(fn.GetFullPath());
            item->SetBitmap(m_icons.get(fn.GetExt()));
        }

        file_icons m_icons;
    };

private:
    const wxWindowID m_idClear = wxNewId();
    MyHistory m_history;
    menus_tracker<wxMenu> m_menus;
};

#endif // !__WXOSX__

// Boilerplate:

namespace
{
    static std::once_flag initializationFlag;
    RecentFiles* gs_instance = nullptr;
}

RecentFiles& RecentFiles::Get()
{
    std::call_once(initializationFlag, []() {
        gs_instance = new RecentFiles;
    });
    return *gs_instance;
}

void RecentFiles::CleanUp()
{
    if (gs_instance)
    {
        delete gs_instance;
        gs_instance = nullptr;
    }
}

RecentFiles::RecentFiles() : m_impl(new impl) {}
RecentFiles::~RecentFiles() {}

void RecentFiles::UseMenu(wxMenuItem *menu)
{
    m_impl->UseMenu(menu);
}

void RecentFiles::NoteRecentFile(const wxFileName& fn)
{
    m_impl->NoteRecentFile(fn);
}

#ifdef __WXOSX__
void RecentFiles::MacCreateFakeOpenRecentMenu()
{
    m_impl->MacCreateFakeOpenRecentMenu();
}

void RecentFiles::MacTransferMenuTo(wxMenuBar *bar)
{
    m_impl->MacTransferMenuTo(bar);
}
#endif // __WXOSX__
<|endoftext|>


<commit_before>//===-- LiveInterval.cpp - Live Interval Representation -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveRange and LiveInterval classes.  Given some
// numbering of each the machine instructions an interval [i, j) is said to be a
// live interval for register v if there is no instruction with number j' > j
// such that v is live at j' abd there is no instruction with number i' < i such
// that v is live at i'. In this implementation intervals can have holes,
// i.e. an interval might look like [1,20), [50,65), [1000,1001).  Each
// individual range is represented as an instance of LiveRange, and the whole
// interval is represented as an instance of LiveInterval.
//
//===----------------------------------------------------------------------===//

#include "LiveInterval.h"
#include "Support/STLExtras.h"
#include <iostream>
#include <map>
using namespace llvm;

// An example for liveAt():
//
// this = [1,4), liveAt(0) will return false. The instruction defining this
// spans slots [0,3]. The interval belongs to an spilled definition of the
// variable it represents. This is because slot 1 is used (def slot) and spans
// up to slot 3 (store slot).
//
bool LiveInterval::liveAt(unsigned I) const {
  Ranges::const_iterator r = std::upper_bound(ranges.begin(), ranges.end(), I);

  if (r == ranges.begin())
    return false;

  --r;
  return r->contains(I);
}

// An example for overlaps():
//
// 0: A = ...
// 4: B = ...
// 8: C = A + B ;; last use of A
//
// The live intervals should look like:
//
// A = [3, 11)
// B = [7, x)
// C = [11, y)
//
// A->overlaps(C) should return false since we want to be able to join
// A and C.
bool LiveInterval::overlaps(const LiveInterval& other) const {
  Ranges::const_iterator i = ranges.begin();
  Ranges::const_iterator ie = ranges.end();
  Ranges::const_iterator j = other.ranges.begin();
  Ranges::const_iterator je = other.ranges.end();
  if (i->start < j->start) {
    i = std::upper_bound(i, ie, j->start);
    if (i != ranges.begin()) --i;
  } else if (j->start < i->start) {
    j = std::upper_bound(j, je, i->start);
    if (j != other.ranges.begin()) --j;
  } else {
    return true;
  }

  while (i != ie && j != je) {
    if (i->start == j->start)
      return true;

    if (i->start > j->start) {
      swap(i, j);
      swap(ie, je);
    }
    assert(i->start < j->start);

    if (i->end > j->start)
      return true;
    ++i;
  }

  return false;
}

/// joinable - Two intervals are joinable if the either don't overlap at all
/// or if the destination of the copy is a single assignment value, and it
/// only overlaps with one value in the source interval.
bool LiveInterval::joinable(const LiveInterval &other, unsigned CopyIdx) const {
  return overlaps(other);
}

/// extendIntervalEndTo - This method is used when we want to extend the range
/// specified by I to end at the specified endpoint.  To do this, we should
/// merge and eliminate all ranges that this will overlap with.  The iterator is
/// not invalidated.
void LiveInterval::extendIntervalEndTo(Ranges::iterator I, unsigned NewEnd) {
  assert(I != ranges.end() && "Not a valid interval!");
  unsigned ValId = I->ValId;

  // Search for the first interval that we can't merge with.
  Ranges::iterator MergeTo = next(I);
  for (; MergeTo != ranges.end() && NewEnd >= MergeTo->end; ++MergeTo) {
    assert(MergeTo->ValId == ValId && "Cannot merge with differing values!");
  }

  // If NewEnd was in the middle of an interval, make sure to get its endpoint.
  I->end = std::max(NewEnd, prior(MergeTo)->end);

  // Erase any dead ranges
  ranges.erase(next(I), MergeTo);
}

/// extendIntervalStartTo - This method is used when we want to extend the range
/// specified by I to start at the specified endpoint.  To do this, we should
/// merge and eliminate all ranges that this will overlap with.
LiveInterval::Ranges::iterator
LiveInterval::extendIntervalStartTo(Ranges::iterator I, unsigned NewStart) {
  assert(I != ranges.end() && "Not a valid interval!");
  unsigned ValId = I->ValId;

  // Search for the first interval that we can't merge with.
  Ranges::iterator MergeTo = I;
  do {
    if (MergeTo == ranges.begin()) {
      I->start = NewStart;
      ranges.erase(MergeTo, I);
      return I;
    }
    assert(MergeTo->ValId == ValId && "Cannot merge with differing values!");
    --MergeTo;
  } while (NewStart <= MergeTo->start);

  // If we start in the middle of another interval, just delete a range and
  // extend that interval.
  if (MergeTo->end >= NewStart && MergeTo->ValId == ValId) {
    MergeTo->end = I->end;
  } else {
    // Otherwise, extend the interval right after.
    ++MergeTo;
    MergeTo->start = NewStart;
    MergeTo->end = I->end;
  }

  ranges.erase(next(MergeTo), next(I));
  return MergeTo;
}

LiveInterval::Ranges::iterator
LiveInterval::addRangeFrom(LiveRange LR, Ranges::iterator From) {
  unsigned Start = LR.start, End = LR.end;
  Ranges::iterator it = std::upper_bound(From, ranges.end(), Start);

  // If the inserted interval starts in the middle or right at the end of
  // another interval, just extend that interval to contain the range of LR.
  if (it != ranges.begin()) {
    Ranges::iterator B = prior(it);
    if (LR.ValId == B->ValId) {
      if (B->start <= Start && B->end >= Start) {
        extendIntervalEndTo(B, End);
        return B;
      }
    } else {
      // Check to make sure that we are not overlapping two live ranges with
      // different ValId's.
      assert(B->end <= Start &&
             "Cannot overlap two LiveRanges with differing ValID's");
    }
  }

  // Otherwise, if this range ends in the middle of, or right next to, another
  // interval, merge it into that interval.
  if (it != ranges.end())
    if (LR.ValId == it->ValId) {
      if (it->start <= End) {
        it = extendIntervalStartTo(it, Start);

        // If LR is a complete superset of an interval, we may need to grow its
        // endpoint as well.
        if (End > it->end)
          extendIntervalEndTo(it, End);
        return it;
      }
    } else {
      // Check to make sure that we are not overlapping two live ranges with
      // different ValId's.
      assert(it->start >= End &&
             "Cannot overlap two LiveRanges with differing ValID's");
    }

  // Otherwise, this is just a new range that doesn't interact with anything.
  // Insert it.
  return ranges.insert(it, LR);
}

/// removeRange - Remove the specified range from this interval.  Note that
/// the range must already be in this interval in its entirety.
void LiveInterval::removeRange(unsigned Start, unsigned End) {
  // Find the LiveRange containing this span.
  Ranges::iterator I = std::upper_bound(ranges.begin(), ranges.end(), Start);
  assert(I != ranges.begin() && "Range is not in interval!");
  --I;
  assert(I->contains(Start) && I->contains(End-1) &&
         "Range is not entirely in interval!");

  // If the span we are removing is at the start of the LiveRange, adjust it.
  if (I->start == Start) {
    if (I->end == End)
      ranges.erase(I);  // Removed the whole LiveRange.
    else
      I->start = End;
    return;
  }

  // Otherwise if the span we are removing is at the end of the LiveRange,
  // adjust the other way.
  if (I->end == End) {
    I->start = Start;
    return;
  }

  // Otherwise, we are splitting the LiveRange into two pieces.
  unsigned OldEnd = I->end;
  I->end = Start;   // Trim the old interval.

  // Insert the new one.
  ranges.insert(next(I), LiveRange(End, OldEnd, I->ValId));
}

/// getLiveRangeContaining - Return the live range that contains the
/// specified index, or null if there is none.
LiveRange *LiveInterval::getLiveRangeContaining(unsigned Idx) {
  Ranges::iterator It = std::upper_bound(ranges.begin(), ranges.end(), Idx);
  if (It != ranges.begin()) {
    LiveRange &LR = *prior(It);
    if (LR.contains(Idx))
      return &LR;
  }

  return 0;
}

/// join - Join two live intervals (this, and other) together.  This operation
/// is the result of a copy instruction in the source program, that occurs at
/// index 'CopyIdx' that copies from 'Other' to 'this'.
void LiveInterval::join(LiveInterval &Other, unsigned CopyIdx) {
  LiveRange *SourceLR = Other.getLiveRangeContaining(CopyIdx-1);
  LiveRange *DestLR = getLiveRangeContaining(CopyIdx);
  assert(SourceLR && DestLR && "Not joining due to a copy?");
  unsigned MergedSrcValIdx = SourceLR->ValId;
  unsigned MergedDstValIdx = DestLR->ValId;

  // Join the ranges of other into the ranges of this interval.
  Ranges::iterator InsertPos = ranges.begin();
  std::map<unsigned, unsigned> Dst2SrcIdxMap;
  for (Ranges::iterator I = Other.ranges.begin(),
         E = Other.ranges.end(); I != E; ++I) {
    // Map the ValId in the other live range to the current live range.
    if (I->ValId == MergedSrcValIdx)
      I->ValId = MergedDstValIdx;
    else {
      unsigned &NV = Dst2SrcIdxMap[I->ValId];
      if (NV == 0) NV = getNextValue();
      I->ValId = NV;
    }

    InsertPos = addRangeFrom(*I, InsertPos);
  }

  weight += Other.weight;
}

std::ostream& llvm::operator<<(std::ostream& os, const LiveRange &LR) {
  return os << '[' << LR.start << ',' << LR.end << ':' << LR.ValId << ")";
}

void LiveRange::dump() const {
  std::cerr << *this << "\n";
}

std::ostream& llvm::operator<<(std::ostream& os, const LiveInterval& li) {
  os << "%reg" << li.reg << ',' << li.weight;
  if (li.empty())
    return os << "EMPTY";

  os << " = ";
  for (LiveInterval::Ranges::const_iterator i = li.ranges.begin(),
         e = li.ranges.end(); i != e; ++i)
    os << *i;
  return os;
}

void LiveInterval::dump() const {
  std::cerr << *this << "\n";
}
<commit_msg>In the joiner, merge the small interval into the large interval.  This restores us back to taking about 10.5s on gcc, instead of taking 15.6s!  The net result is that my big patches have hand no significant effect on compile time or code quality.  heh.<commit_after>//===-- LiveInterval.cpp - Live Interval Representation -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveRange and LiveInterval classes.  Given some
// numbering of each the machine instructions an interval [i, j) is said to be a
// live interval for register v if there is no instruction with number j' > j
// such that v is live at j' abd there is no instruction with number i' < i such
// that v is live at i'. In this implementation intervals can have holes,
// i.e. an interval might look like [1,20), [50,65), [1000,1001).  Each
// individual range is represented as an instance of LiveRange, and the whole
// interval is represented as an instance of LiveInterval.
//
//===----------------------------------------------------------------------===//

#include "LiveInterval.h"
#include "Support/STLExtras.h"
#include <iostream>
#include <map>
using namespace llvm;

// An example for liveAt():
//
// this = [1,4), liveAt(0) will return false. The instruction defining this
// spans slots [0,3]. The interval belongs to an spilled definition of the
// variable it represents. This is because slot 1 is used (def slot) and spans
// up to slot 3 (store slot).
//
bool LiveInterval::liveAt(unsigned I) const {
  Ranges::const_iterator r = std::upper_bound(ranges.begin(), ranges.end(), I);

  if (r == ranges.begin())
    return false;

  --r;
  return r->contains(I);
}

// An example for overlaps():
//
// 0: A = ...
// 4: B = ...
// 8: C = A + B ;; last use of A
//
// The live intervals should look like:
//
// A = [3, 11)
// B = [7, x)
// C = [11, y)
//
// A->overlaps(C) should return false since we want to be able to join
// A and C.
bool LiveInterval::overlaps(const LiveInterval& other) const {
  Ranges::const_iterator i = ranges.begin();
  Ranges::const_iterator ie = ranges.end();
  Ranges::const_iterator j = other.ranges.begin();
  Ranges::const_iterator je = other.ranges.end();
  if (i->start < j->start) {
    i = std::upper_bound(i, ie, j->start);
    if (i != ranges.begin()) --i;
  } else if (j->start < i->start) {
    j = std::upper_bound(j, je, i->start);
    if (j != other.ranges.begin()) --j;
  } else {
    return true;
  }

  while (i != ie && j != je) {
    if (i->start == j->start)
      return true;

    if (i->start > j->start) {
      swap(i, j);
      swap(ie, je);
    }
    assert(i->start < j->start);

    if (i->end > j->start)
      return true;
    ++i;
  }

  return false;
}

/// joinable - Two intervals are joinable if the either don't overlap at all
/// or if the destination of the copy is a single assignment value, and it
/// only overlaps with one value in the source interval.
bool LiveInterval::joinable(const LiveInterval &other, unsigned CopyIdx) const {
  return overlaps(other);
}

/// extendIntervalEndTo - This method is used when we want to extend the range
/// specified by I to end at the specified endpoint.  To do this, we should
/// merge and eliminate all ranges that this will overlap with.  The iterator is
/// not invalidated.
void LiveInterval::extendIntervalEndTo(Ranges::iterator I, unsigned NewEnd) {
  assert(I != ranges.end() && "Not a valid interval!");
  unsigned ValId = I->ValId;

  // Search for the first interval that we can't merge with.
  Ranges::iterator MergeTo = next(I);
  for (; MergeTo != ranges.end() && NewEnd >= MergeTo->end; ++MergeTo) {
    assert(MergeTo->ValId == ValId && "Cannot merge with differing values!");
  }

  // If NewEnd was in the middle of an interval, make sure to get its endpoint.
  I->end = std::max(NewEnd, prior(MergeTo)->end);

  // Erase any dead ranges
  ranges.erase(next(I), MergeTo);
}

/// extendIntervalStartTo - This method is used when we want to extend the range
/// specified by I to start at the specified endpoint.  To do this, we should
/// merge and eliminate all ranges that this will overlap with.
LiveInterval::Ranges::iterator
LiveInterval::extendIntervalStartTo(Ranges::iterator I, unsigned NewStart) {
  assert(I != ranges.end() && "Not a valid interval!");
  unsigned ValId = I->ValId;

  // Search for the first interval that we can't merge with.
  Ranges::iterator MergeTo = I;
  do {
    if (MergeTo == ranges.begin()) {
      I->start = NewStart;
      ranges.erase(MergeTo, I);
      return I;
    }
    assert(MergeTo->ValId == ValId && "Cannot merge with differing values!");
    --MergeTo;
  } while (NewStart <= MergeTo->start);

  // If we start in the middle of another interval, just delete a range and
  // extend that interval.
  if (MergeTo->end >= NewStart && MergeTo->ValId == ValId) {
    MergeTo->end = I->end;
  } else {
    // Otherwise, extend the interval right after.
    ++MergeTo;
    MergeTo->start = NewStart;
    MergeTo->end = I->end;
  }

  ranges.erase(next(MergeTo), next(I));
  return MergeTo;
}

LiveInterval::Ranges::iterator
LiveInterval::addRangeFrom(LiveRange LR, Ranges::iterator From) {
  unsigned Start = LR.start, End = LR.end;
  Ranges::iterator it = std::upper_bound(From, ranges.end(), Start);

  // If the inserted interval starts in the middle or right at the end of
  // another interval, just extend that interval to contain the range of LR.
  if (it != ranges.begin()) {
    Ranges::iterator B = prior(it);
    if (LR.ValId == B->ValId) {
      if (B->start <= Start && B->end >= Start) {
        extendIntervalEndTo(B, End);
        return B;
      }
    } else {
      // Check to make sure that we are not overlapping two live ranges with
      // different ValId's.
      assert(B->end <= Start &&
             "Cannot overlap two LiveRanges with differing ValID's");
    }
  }

  // Otherwise, if this range ends in the middle of, or right next to, another
  // interval, merge it into that interval.
  if (it != ranges.end())
    if (LR.ValId == it->ValId) {
      if (it->start <= End) {
        it = extendIntervalStartTo(it, Start);

        // If LR is a complete superset of an interval, we may need to grow its
        // endpoint as well.
        if (End > it->end)
          extendIntervalEndTo(it, End);
        return it;
      }
    } else {
      // Check to make sure that we are not overlapping two live ranges with
      // different ValId's.
      assert(it->start >= End &&
             "Cannot overlap two LiveRanges with differing ValID's");
    }

  // Otherwise, this is just a new range that doesn't interact with anything.
  // Insert it.
  return ranges.insert(it, LR);
}

/// removeRange - Remove the specified range from this interval.  Note that
/// the range must already be in this interval in its entirety.
void LiveInterval::removeRange(unsigned Start, unsigned End) {
  // Find the LiveRange containing this span.
  Ranges::iterator I = std::upper_bound(ranges.begin(), ranges.end(), Start);
  assert(I != ranges.begin() && "Range is not in interval!");
  --I;
  assert(I->contains(Start) && I->contains(End-1) &&
         "Range is not entirely in interval!");

  // If the span we are removing is at the start of the LiveRange, adjust it.
  if (I->start == Start) {
    if (I->end == End)
      ranges.erase(I);  // Removed the whole LiveRange.
    else
      I->start = End;
    return;
  }

  // Otherwise if the span we are removing is at the end of the LiveRange,
  // adjust the other way.
  if (I->end == End) {
    I->start = Start;
    return;
  }

  // Otherwise, we are splitting the LiveRange into two pieces.
  unsigned OldEnd = I->end;
  I->end = Start;   // Trim the old interval.

  // Insert the new one.
  ranges.insert(next(I), LiveRange(End, OldEnd, I->ValId));
}

/// getLiveRangeContaining - Return the live range that contains the
/// specified index, or null if there is none.
LiveRange *LiveInterval::getLiveRangeContaining(unsigned Idx) {
  Ranges::iterator It = std::upper_bound(ranges.begin(), ranges.end(), Idx);
  if (It != ranges.begin()) {
    LiveRange &LR = *prior(It);
    if (LR.contains(Idx))
      return &LR;
  }

  return 0;
}

/// join - Join two live intervals (this, and other) together.  This operation
/// is the result of a copy instruction in the source program, that occurs at
/// index 'CopyIdx' that copies from 'Other' to 'this'.
void LiveInterval::join(LiveInterval &Other, unsigned CopyIdx) {
  LiveRange *SourceLR = Other.getLiveRangeContaining(CopyIdx-1);
  LiveRange *DestLR = getLiveRangeContaining(CopyIdx);
  assert(SourceLR && DestLR && "Not joining due to a copy?");
  unsigned MergedSrcValIdx = SourceLR->ValId;
  unsigned MergedDstValIdx = DestLR->ValId;

  // Try to do the least amount of work possible.  In particular, if there are
  // more liverange chunks in the other set than there are in the 'this' set,
  // swap sets to merge the fewest chunks in possible.
  if (Other.ranges.size() > ranges.size()) {
    std::swap(MergedSrcValIdx, MergedDstValIdx);
    std::swap(ranges, Other.ranges);
    std::swap(NumValues, Other.NumValues);
  }

  // Join the ranges of other into the ranges of this interval.
  Ranges::iterator InsertPos = ranges.begin();
  std::map<unsigned, unsigned> Dst2SrcIdxMap;
  for (Ranges::iterator I = Other.ranges.begin(),
         E = Other.ranges.end(); I != E; ++I) {
    // Map the ValId in the other live range to the current live range.
    if (I->ValId == MergedSrcValIdx)
      I->ValId = MergedDstValIdx;
    else {
      unsigned &NV = Dst2SrcIdxMap[I->ValId];
      if (NV == 0) NV = getNextValue();
      I->ValId = NV;
    }

    InsertPos = addRangeFrom(*I, InsertPos);
  }

  weight += Other.weight;
}

std::ostream& llvm::operator<<(std::ostream& os, const LiveRange &LR) {
  return os << '[' << LR.start << ',' << LR.end << ':' << LR.ValId << ")";
}

void LiveRange::dump() const {
  std::cerr << *this << "\n";
}

std::ostream& llvm::operator<<(std::ostream& os, const LiveInterval& li) {
  os << "%reg" << li.reg << ',' << li.weight;
  if (li.empty())
    return os << "EMPTY";

  os << " = ";
  for (LiveInterval::Ranges::const_iterator i = li.ranges.begin(),
         e = li.ranges.end(); i != e; ++i)
    os << *i;
  return os;
}

void LiveInterval::dump() const {
  std::cerr << *this << "\n";
}
<|endoftext|>


<commit_before><commit_msg>Fix -std option.<commit_after><|endoftext|>


<commit_before>#include"block.h"
#include<tgmath.h>
#include"validator.h"
#include<iostream>
#include"keccak.h"
#include"rlp.h"
#include"trie.h"
#include<iterator>

using namespace std;

void validateAll(const Block& parent, const Block& child) {
    unsigned short int error_found = 0; //signals if some validation faile 0 means nothing failed;
    if (validateParentHash(parent, child) != 0) {
            error_found = 1;
            cout << "Parent hash is invalid." << endl;
    }
    if (validateBlockNumber(parent, child) != 0) {
            error_found = 1;
            cout << "Block number is invalid." << endl;
    }
    if (validateDifficulty(parent, child) != 0) {
            error_found = 1;
            cout << "Block difficulty is invalid." << endl;
    }
    if (validateGasLimit(parent, child) != 0) {
            error_found = 1;
            cout << "Gas limit is invalid." << endl;
    }
    if (validateTimeStamp(parent, child) != 0) {
            error_found = 1;
            cout << "Timestamp is invalid." << endl;
    }
    if (validateTransactionsRoot(child) != 0) {
            error_found = 1;
            cout << "Hash of root of transactions tree is invalid." << endl;
    }
    if (validateNonce(parent, child) != 0) {
            error_found = 1;
            cout << "Nonce is invalid." << endl;
    }
    if (validateMixHash(parent, child) != 0) {
            error_found = 1;
            cout << "Mixh hash is invalid." << endl;
    }
    if (validateReceipts(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transaction receipts tree is not valid." << endl;
    }
    if (validateLogsBloom(parent, child) != 0) {
            error_found = 1;
            cout << "Logs Bloom filters are invalid." << endl;
    }
    if (error_found == 0) {
            cout << "Block is valid." << endl;
    }
}

/* validates The Keccak 256-bit hash of the parent block's header, in its entirety
 * * @param Block
 * @ param Block
 * @return int
*/
int validateParentHash(const Block& parent, const Block& child) {
    /*now getting parts of Block header, creating a vector of RLPfield
     * then serializing them through RLP.serialize and calculating their hash
    */
    Header header = parent.header();
    vector<uint8_t> headerbytes = header.toRLP();
    vector<uint8_t> parentheaderhash = keccak(headerbytes);
    vector<uint8_t> childhash = child.header().parentHash();
    if (parentheaderhash == childhash) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateBlockNumber(const Block& parent, const Block& child) {
    if (parent.header().number() == (child.header().number() - 1)) {
            return 0;
    }
    else {
            return 1;
    }
}

//difficulty formula taken from https://ethereum.stackexchange.com/questions/1880/how-is-the-mining-difficulty-calculated-on-ethereum
int validateDifficulty(const Block& parent, const Block& child) {
    size_t block_diff = fmax(parent.header().difficulty() + parent.header().difficulty() / 2048 * fmax(1 - (child.header().timestamp() - parent.header().timestamp()) / 10, -99) + pow(2, ((child.header().number() / 100000) - 2)), 131072);
    if (block_diff == child.header().difficulty()) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateGasLimit(const Block& parent, const Block& child) {
    if ((child.header().gasLimit() < parent.header().gasLimit() + (parent.header().gasLimit() / 1024)) && (child.header().gasLimit() > parent.header().gasLimit() - (parent.header().gasLimit() / 1024))) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateTimeStamp(const Block& parent, const Block& child) {
    if (child.header().timestamp() > parent.header().timestamp()) {
            return 0;
    }
    else {
            return 1;
    }
}

//nothing for now, waiting for merkle trees
int validateTransactionsRoot(const Block& block) {
    /*vector<Transaction> transactions = block.transactions();
    trie::Trie t; //Merkle Patricia trie for transactions
    vector<uint8_t> computedhash; //hash computed from reconstructed tree
    for (vector<Transaction>::const_iterator i = transactions.begin(); i != transactions.end(); ++i) {
            unsigned int position = distance(transactions.cbegin(), i); //position of transaction in the vector
            t.update(numberToVector(position), i->toRLP());
    }
    computedhash = t.hash();
    if (computedhash == block.header().transactionsRoot()) {
            return 0;
    }
    else {
            return 1;
    }*/
    return 0;
}

int validateNonce(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of nonce requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateMixHash(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of mixHash requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateReceipts(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of receipts trie requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateLogsBloom(const Block& parent, const Block& child) {
    /*This method is not implemented because we would need to implement or use EVM (Ethereum virtual machine). We think that this is strongly out of scope of this project. */
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

<commit_msg>improved validator documentation<commit_after>#include"block.h"
#include<tgmath.h>
#include"validator.h"
#include<iostream>
#include"keccak.h"
#include"rlp.h"
#include"trie.h"
#include<iterator>

using namespace std;

/** runs all validation checks, prints errors
 * @param Block  - parent block
 * @param Block - child block
 * @return void
 */
void validateAll(const Block& parent, const Block& child) {
    unsigned short int error_found = 0; //signals if some validation faile 0 means nothing failed;
    if (validateParentHash(parent, child) != 0) {
            error_found = 1;
            cout << "Parent hash is invalid." << endl;
    }
    if (validateBlockNumber(parent, child) != 0) {
            error_found = 1;
            cout << "Block number is invalid." << endl;
    }
    if (validateDifficulty(parent, child) != 0) {
            error_found = 1;
            cout << "Block difficulty is invalid." << endl;
    }
    if (validateGasLimit(parent, child) != 0) {
            error_found = 1;
            cout << "Gas limit is invalid." << endl;
    }
    if (validateTimeStamp(parent, child) != 0) {
            error_found = 1;
            cout << "Timestamp is invalid." << endl;
    }
    if (validateTransactionsRoot(child) != 0) {
            error_found = 1;
            cout << "Hash of root of transactions tree is invalid." << endl;
    }
    if (validateNonce(parent, child) != 0) {
            error_found = 1;
            cout << "Nonce is invalid." << endl;
    }
    if (validateMixHash(parent, child) != 0) {
            error_found = 1;
            cout << "Mixh hash is invalid." << endl;
    }
    if (validateReceipts(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transaction receipts tree is not valid." << endl;
    }
    if (validateLogsBloom(parent, child) != 0) {
            error_found = 1;
            cout << "Logs Bloom filters are invalid." << endl;
    }
    if (error_found == 0) {
            cout << "Block is valid." << endl;
    }
}

/* verifies if parent header hash of child block corresponds to hash of parent block header
 * * @param Block - parent block
 * @ param Block - child block
 * @return int - 0 if OK, else 1
*/
int validateParentHash(const Block& parent, const Block& child) {
    /*now getting parts of Block header, creating a vector of RLPfield
     * then serializing them through RLP.serialize and calculating their hash
    */
    Header header = parent.header();
    vector<uint8_t> headerbytes = header.toRLP();
    vector<uint8_t> parentheaderhash = keccak(headerbytes);
    vector<uint8_t> childhash = child.header().parentHash();
    if (parentheaderhash == childhash) {
            return 0;
    }
    else {
            return 1;
    }
}

/*verifies if child block has right block number according to parent block, see Yellow paper - Block header validity
 * @param Block - parent block
 * @param Block - child block
 * @return int - 0 if OK, else 1
 */
int validateBlockNumber(const Block& parent, const Block& child) {
    if (parent.header().number() == (child.header().number() - 1)) {
            return 0;
    }
    else {
            return 1;
    }
}

/* Verifies if child block's difficulty is in correct range limited by parent block, see Yellow paper - Block header validity
 * @param Block - parent block
 * @param Block - child block
 * @return int - 0 if OK, else 1
 */
int validateDifficulty(const Block& parent, const Block& child) {
    //difficulty formula taken from https://ethereum.stackexchange.com/questions/1880/how-is-the-mining-difficulty-calculated-on-ethereum and from Yellow paper
    size_t block_diff = fmax(parent.header().difficulty() + parent.header().difficulty() / 2048 * fmax(1 - (child.header().timestamp() - parent.header().timestamp()) / 10, -99) + pow(2, ((child.header().number() / 100000) - 2)), 131072);
    if (block_diff == child.header().difficulty()) {
            return 0;
    }
    else {
            return 1;
    }
}

/* validates if gas limit of child is in accordance with gas limit of parent, see Yellow paper - block header validity
 * @param Block - parent
 * @param Block - child
 * @return int - 0 if OK, else 1
 */
int validateGasLimit(const Block& parent, const Block& child) {
    if ((child.header().gasLimit() < parent.header().gasLimit() + (parent.header().gasLimit() / 1024)) && (child.header().gasLimit() > parent.header().gasLimit() - (parent.header().gasLimit() / 1024))) {
            return 0;
    }
    else {
            return 1;
    }
}

/* verifies if child's timestamp is greater then parent's timestamp
 * @param Block - parent
 * @param Block - child
 * @return int - 0 if OK, else 1
 */
int validateTimeStamp(const Block& parent, const Block& child) {
    if (child.header().timestamp() > parent.header().timestamp()) {
            return 0;
    }
    else {
            return 1;
    }
}

/* verifies if transactions root hash stored in header corresponds to hash of root of transactions tree stored in block
 * @param Block - block to check
 * @return int - 0 if OK, else 1
 */
int validateTransactionsRoot(const Block& block) {
    /*vector<Transaction> transactions = block.transactions();
    trie::Trie t; //Merkle Patricia trie for transactions
    vector<uint8_t> computedhash; //hash computed from reconstructed tree
    for (vector<Transaction>::const_iterator i = transactions.begin(); i != transactions.end(); ++i) {
            unsigned int position = distance(transactions.cbegin(), i); //position of transaction in the vector
            t.update(numberToVector(position), i->toRLP());
    }
    computedhash = t.hash();
    if (computedhash == block.header().transactionsRoot()) {
            return 0;
    }
    else {
            return 1;
    }*/
    return 0;
}

int validateNonce(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of nonce requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateMixHash(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of mixHash requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateReceipts(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of receipts trie requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateLogsBloom(const Block& parent, const Block& child) {
    /*This method is not implemented because we would need to implement or use EVM (Ethereum virtual machine). We think that this is strongly out of scope of this project. */
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

<|endoftext|>