<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2022.  All rights reserved
 */
#include "Stroika/Frameworks/StroikaPreComp.h"

#include <iostream>

#include "Stroika/Foundation/Characters/FloatConversion.h"
#include "Stroika/Foundation/Characters/String2Int.h"
#include "Stroika/Foundation/Characters/ToString.h"
#include "Stroika/Foundation/Common/Property.h"
#include "Stroika/Foundation/DataExchange/InternetMediaTypeRegistry.h"
#include "Stroika/Foundation/IO/Network/HTTP/Exception.h"
#include "Stroika/Foundation/IO/Network/HTTP/Headers.h"
#include "Stroika/Foundation/IO/Network/HTTP/Methods.h"
#include "Stroika/Foundation/Streams/TextReader.h"

#include "Stroika/Frameworks/WebServer/ConnectionManager.h"
#include "Stroika/Frameworks/WebServer/Router.h"
#include "Stroika/Frameworks/WebService/Server/Basic.h"
#include "Stroika/Frameworks/WebService/Server/VariantValue.h"

#include "WebServer.h"

#include "AppVersion.h"

using namespace std;

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::IO::Network;

using namespace Stroika::Frameworks::WebServer;
using namespace Stroika::Frameworks::WebService;
using namespace Stroika::Frameworks::WebService::Server;
using namespace Stroika::Frameworks::WebService::Server::VariantValue;

using Memory::BLOB;
using Stroika::Frameworks::WebServer::Request;
using Stroika::Frameworks::WebServer::Response;

using namespace StroikaSample::WebServices;

namespace {
    const Common::ConstantProperty<Headers> kDefaultResponseHeaders_{[] () {
        Headers h;
        h.server = L"Stroika-Sample-WebServices/"_k + AppVersion::kVersion.AsMajorMinorString ();
        return h;
    }};
}

/*
 *  It's often helpful to structure together, routes, special interceptors, with your connection manager, to package up
 *  all the logic /options for HTTP interface.
 *
 *  This particular organization also makes it easy to save instance variables with the webserver (like a pointer to a handler)
 *  and accesss them from the Route handler functions.
 */
class WebServer::Rep_ {
public:
    const Sequence<Route> kRoutes_;        // rules saying how to map urls to code
    shared_ptr<IWSAPI>    fWSImpl_;        // application logic actually handling webservices
    ConnectionManager     fConnectionMgr_; // manage http connection objects, thread pool, etc

    static const WebServiceMethodDescription kVariables_;

    static const WebServiceMethodDescription kPlus_;
    static const WebServiceMethodDescription kMinus;
    static const WebServiceMethodDescription kTimes;
    static const WebServiceMethodDescription kDivide;

    Rep_ (uint16_t portNumber, const shared_ptr<IWSAPI>& wsImpl)
        : kRoutes_{
              Route{L""_RegEx, DefaultPage_},

              Route{HTTP::MethodsRegEx::kPost, L"SetAppState"_RegEx, SetAppState_},

              Route{L"FRED"_RegEx, [] (Request*, Response* response) {
                        response->write (L"FRED");
                        response->contentType = InternetMediaTypes::kText_PLAIN;
                    }},

              /*
               * the 'variable' API demonstrates a typical REST style CRUD usage - where the 'arguments' mainly come from
               * the URL itself.
               */
              Route{L"variables(/?)"_RegEx, [this] (Message* m) {
                        WriteResponse (&m->rwResponse (), kVariables_, kMapper.FromObject (fWSImpl_->Variables_GET ()));
                    }},
              Route{L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        WriteResponse (&m->rwResponse (), kVariables_, kMapper.FromObject (fWSImpl_->Variables_GET (varName)));
                    }},
              Route{HTTP::MethodsRegEx::kPostOrPut, L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        optional<Number> number;
                        // demo getting argument from the body
                        if (not number) {
                            // read if content-type is text (not json)
                            if (m->request ().contentType () and InternetMediaTypeRegistry::Get ().IsA (InternetMediaTypes::kText_PLAIN, *m->request ().contentType ())) {
                                String argsAsString = Streams::TextReader::New (m->rwRequest ().GetBody ()).ReadAll ();
                                number              = kMapper.ToObject<Number> (DataExchange::VariantValue{argsAsString});
                            }
                        }
                        // demo getting argument from the query argument
                        if (not number) {
                            static const String                         kValueParamName_ = L"value"sv;
                            Mapping<String, DataExchange::VariantValue> args             = PickoutParamValuesFromURL (&m->request ());
                            number                                                       = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
                        }
                        // demo getting either query arg, or url encoded arg
                        if (not number) {
                            static const String kValueParamName_ = L"value"sv;
                            // NOTE - PickoutParamValues combines PickoutParamValuesFromURL, and PickoutParamValuesFromBody. You can use
                            // Either one of those instead. PickoutParamValuesFromURL assumes you know the name of the parameter, and its
                            // encoded in the query string. PickoutParamValuesFromBody assumes you have something equivilent you can parse ouf
                            // of the body, either json encoded or form-encoded (as of 2.1d23, only json encoded supported)
                            Mapping<String, DataExchange::VariantValue> args = PickoutParamValues (&m->rwRequest ());
                            number                                           = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
                        }
                        if (not number) {
                            Execution::Throw (HTTP::ClientErrorException{L"Expected argument to PUT/POST variable"sv});
                        }
                        fWSImpl_->Variables_SET (varName, *number);
                        WriteResponse (&m->rwResponse (), kVariables_);
                    }},
              Route{HTTP::MethodsRegEx::kDelete, L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        fWSImpl_->Variables_DELETE (varName);
                        WriteResponse (&m->rwResponse (), kVariables_);
                    }},

              /*
               *    plus, minus, times, and divide, test-void-return all all demonstrate passing in variables through either the POST body, or query-arguments.
               */
              Route{HTTP::MethodsRegEx::kPost, L"plus"_RegEx, mkRequestHandler (kPlus_, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->plus (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"minus"_RegEx, mkRequestHandler (kMinus, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->minus (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"times"_RegEx, mkRequestHandler (kTimes, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->times (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"divide"_RegEx, mkRequestHandler (kDivide, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->divide (arg1, arg2); }})},
              Route{L"test-void-return"_RegEx, mkRequestHandler (WebServiceMethodDescription{}, Model::kMapper, Traversal::Iterable<String>{L"err-if-more-than-10"}, function<void (double)>{[] (double check) {
                                    if (check > 10) {
                                        Execution::Throw (Execution::Exception{L"more than 10"sv});
                                    } }})},

          } // clang-format off
        , fWSImpl_ { wsImpl }
#if __cpp_designated_initializers
        , fConnectionMgr_ {
            SocketAddresses (InternetAddresses_Any (), portNumber),
                kRoutes_,
                ConnectionManager::Options { .fBindFlags = Socket::BindFlags{}, .fDefaultResponseHeaders = kDefaultResponseHeaders_ }
        }
#else
        , fConnectionMgr_ {
            SocketAddresses (InternetAddresses_Any (), portNumber),
                kRoutes_,
                ConnectionManager::Options { nullopt, nullopt, Socket::BindFlags{}, kDefaultResponseHeaders_ }
        }
#endif
    // clang-format on
    {
        // @todo - move this to some framework-specific regtests...
        using VariantValue         = DataExchange::VariantValue;
        Sequence<VariantValue> tmp = OrderParamValues (Iterable<String>{L"page", L"xxx"}, PickoutParamValuesFromURL (URI{L"http://www.sophist.com?page=5"}));
        Assert (tmp.size () == 2);
        Assert (tmp[0] == 5);
        Assert (tmp[1] == nullptr);
    }
    // Can declare arguments as Request*,Response*
    static void DefaultPage_ (Request*, Response* response)
    {
        WriteDocsPage (
            response,
            Sequence<WebServiceMethodDescription>{
                kVariables_,
                kPlus_,
                kMinus,
                kTimes,
                kDivide,
            },
            DocsOptions{L"Stroika Sample WebService - Web Methods"_k, L"Note - curl lines all in bash quoting syntax"_k});
    }
    static void SetAppState_ (Message* message)
    {
        String argsAsString = Streams::TextReader::New (message->rwRequest ().GetBody ()).ReadAll ();
        message->rwResponse ().writeln (L"
Hi SetAppState (" + argsAsString.As<wstring> () + L")
");
        message->rwResponse ().contentType = InternetMediaTypes::kHTML;
    }
};

/*
 *  Documentation on WSAPIs
 */
const WebServiceMethodDescription WebServer::Rep_::kVariables_
{
    L"variables"_k,
        Set<String>{HTTP::Methods::kGet, HTTP::Methods::kPost, HTTP::Methods::kDelete},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv}
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl http://localhost:8080/variables -v --output -",
            L"curl http://localhost:8080/variables/x -v --output -",
            L"curl  -X POST http://localhost:8080/variables/x -v --output -",
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"value\": 3}' http://localhost:8080/variables/x --output -",
            L"curl -H \"Content-Type: text/plain\" -X POST -d 3 http://localhost:8080/variables/x --output -"},
        Sequence<String>{L"@todo - this is a rough draft (but functional). It could use alot of cleanup and review to see WHICH way I recommend using, and just provide the recommended ways in samples"},
};

const WebServiceMethodDescription WebServer::Rep_::kPlus_
{
    L"plus"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\": 3, \"arg2\": 5 }' http://localhost:8080/plus --output -",
        },
        Sequence<String>{L"add the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kMinus
{
    L"minus"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\": 4.5, \"arg2\": -3.23 }' http://localhost:8080/minus --output -",
        },
        Sequence<String>{L"subtract the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kTimes
{
    L"times"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + 4i\", \"arg2\": 3.2 }' http://localhost:8080/times --output -",
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + i\", \"arg2\": \"2 - i\" }' http://localhost:8080/times --output -",
        },
        Sequence<String>{L"multiply the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kDivide
{
    L"divide"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + i\", \"arg2\": 0 }' http://localhost:8080/divide --output -",
        },
        Sequence<String>{L"divide the two argument numbers"},
};

WebServer::WebServer (uint16_t portNumber, const shared_ptr<IWSAPI>& wsImpl)
    : fRep_{make_shared<Rep_> (portNumber, wsImpl)}
{
}
<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2022.  All rights reserved
 */
#include "Stroika/Frameworks/StroikaPreComp.h"

#include <iostream>

#include "Stroika/Foundation/Characters/FloatConversion.h"
#include "Stroika/Foundation/Characters/String2Int.h"
#include "Stroika/Foundation/Characters/ToString.h"
#include "Stroika/Foundation/Common/Property.h"
#include "Stroika/Foundation/DataExchange/InternetMediaTypeRegistry.h"
#include "Stroika/Foundation/IO/Network/HTTP/Exception.h"
#include "Stroika/Foundation/IO/Network/HTTP/Headers.h"
#include "Stroika/Foundation/IO/Network/HTTP/Methods.h"
#include "Stroika/Foundation/Streams/TextReader.h"

#include "Stroika/Frameworks/WebServer/ConnectionManager.h"
#include "Stroika/Frameworks/WebServer/Router.h"
#include "Stroika/Frameworks/WebService/Server/Basic.h"
#include "Stroika/Frameworks/WebService/Server/VariantValue.h"

#include "WebServer.h"

#include "AppVersion.h"

using namespace std;

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::IO::Network;

using namespace Stroika::Frameworks::WebServer;
using namespace Stroika::Frameworks::WebService;
using namespace Stroika::Frameworks::WebService::Server;
using namespace Stroika::Frameworks::WebService::Server::VariantValue;

using Memory::BLOB;
using Stroika::Frameworks::WebServer::Request;
using Stroika::Frameworks::WebServer::Response;

using namespace StroikaSample::WebServices;

namespace {
    const Common::ConstantProperty<Headers> kDefaultResponseHeaders_{[] () {
        Headers h;
        h.server = L"Stroika-Sample-WebServices/"_k + AppVersion::kVersion.AsMajorMinorString ();
        return h;
    }};
}

/*
 *  It's often helpful to structure together, routes, special interceptors, with your connection manager, to package up
 *  all the logic /options for HTTP interface.
 *
 *  This particular organization also makes it easy to save instance variables with the webserver (like a pointer to a handler)
 *  and accesss them from the Route handler functions.
 */
class WebServer::Rep_ {
public:
    const Sequence<Route> kRoutes_;        // rules saying how to map urls to code
    shared_ptr<IWSAPI>    fWSImpl_;        // application logic actually handling webservices
    ConnectionManager     fConnectionMgr_; // manage http connection objects, thread pool, etc

    static const WebServiceMethodDescription kVariables_;

    static const WebServiceMethodDescription kPlus_;
    static const WebServiceMethodDescription kMinus;
    static const WebServiceMethodDescription kTimes;
    static const WebServiceMethodDescription kDivide;

    Rep_ (uint16_t portNumber, const shared_ptr<IWSAPI>& wsImpl)
        : kRoutes_{
              Route{L""_RegEx, DefaultPage_},

              Route{HTTP::MethodsRegEx::kPost, L"SetAppState"_RegEx, SetAppState_},

              Route{L"FRED"_RegEx, [] (Request*, Response* response) {
                        response->write (L"FRED");
                        response->contentType = InternetMediaTypes::kText_PLAIN;
                    }},

              /*
               * the 'variable' API demonstrates a typical REST style CRUD usage - where the 'arguments' mainly come from
               * the URL itself.
               */
              Route{L"variables(/?)"_RegEx, [this] (Message* m) {
                        WriteResponse (&m->rwResponse (), kVariables_, kMapper.FromObject (fWSImpl_->Variables_GET ()));
                    }},
              Route{L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        WriteResponse (&m->rwResponse (), kVariables_, kMapper.FromObject (fWSImpl_->Variables_GET (varName)));
                    }},
              Route{HTTP::MethodsRegEx::kPostOrPut, L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        optional<Number> number;
                        // demo getting argument from the body
                        if (not number) {
                            // read if content-type is text (not json)
                            if (m->request ().contentType () and InternetMediaTypeRegistry::Get ().IsA (InternetMediaTypes::kText_PLAIN, *m->request ().contentType ())) {
                                String argsAsString = Streams::TextReader::New (m->rwRequest ().GetBody ()).ReadAll ();
                                number              = kMapper.ToObject<Number> (DataExchange::VariantValue{argsAsString});
                            }
                        }
                        // demo getting argument from the query argument
                        if (not number) {
                            static const String                         kValueParamName_ = L"value"sv;
                            Mapping<String, DataExchange::VariantValue> args             = PickoutParamValuesFromURL (&m->request ());
                            number                                                       = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
                        }
                        // demo getting either query arg, or url encoded arg
                        if (not number) {
                            static const String kValueParamName_ = L"value"sv;
                            // NOTE - PickoutParamValues combines PickoutParamValuesFromURL, and PickoutParamValuesFromBody. You can use
                            // Either one of those instead. PickoutParamValuesFromURL assumes you know the name of the parameter, and its
                            // encoded in the query string. PickoutParamValuesFromBody assumes you have something equivilent you can parse ouf
                            // of the body, either json encoded or form-encoded (as of 2.1d23, only json encoded supported)
                            Mapping<String, DataExchange::VariantValue> args = PickoutParamValues (&m->rwRequest ());
                            number                                           = Model::kMapper.ToObject<Number> (args.LookupValue (kValueParamName_));
                        }
                        if (not number) {
                            Execution::Throw (HTTP::ClientErrorException{L"Expected argument to PUT/POST variable"sv});
                        }
                        fWSImpl_->Variables_SET (varName, *number);
                        WriteResponse (&m->rwResponse (), kVariables_);
                    }},
              Route{HTTP::MethodsRegEx::kDelete, L"variables/(.+)"_RegEx, [this] (Message* m, const String& varName) {
                        fWSImpl_->Variables_DELETE (varName);
                        WriteResponse (&m->rwResponse (), kVariables_);
                    }},

              /*
               *    plus, minus, times, and divide, test-void-return all all demonstrate passing in variables through either the POST body, or query-arguments.
               */
              Route{HTTP::MethodsRegEx::kPost, L"plus"_RegEx, mkRequestHandler (kPlus_, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->plus (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"minus"_RegEx, mkRequestHandler (kMinus, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->minus (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"times"_RegEx, mkRequestHandler (kTimes, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->times (arg1, arg2); }})},
              Route{HTTP::MethodsRegEx::kPost, L"divide"_RegEx, mkRequestHandler (kDivide, Model::kMapper, Traversal::Iterable<String>{L"arg1", L"arg2"}, function<Number (Number, Number)>{[this] (Number arg1, Number arg2) { return fWSImpl_->divide (arg1, arg2); }})},
              Route{L"test-void-return"_RegEx, mkRequestHandler (WebServiceMethodDescription{}, Model::kMapper, Traversal::Iterable<String>{L"err-if-more-than-10"}, function<void (double)>{[] (double check) {
                                    if (check > 10) {
                                        Execution::Throw (Execution::Exception{L"more than 10"sv});
                                    } }})},

          } // clang-format off
        , fWSImpl_ { wsImpl }
#if __cpp_designated_initializers
        , fConnectionMgr_ {
            SocketAddresses (InternetAddresses_Any (), portNumber),
                kRoutes_,
                ConnectionManager::Options { .fBindFlags = Socket::BindFlags{}, .fDefaultResponseHeaders = kDefaultResponseHeaders_ }
        }
#else
        , fConnectionMgr_ {
            SocketAddresses (InternetAddresses_Any (), portNumber),
                kRoutes_,
                ConnectionManager::Options { nullopt, nullopt, Socket::BindFlags{}, kDefaultResponseHeaders_ }
        }
#endif
    // clang-format on
    {
        // @todo - move this to some framework-specific regtests...
        using VariantValue         = DataExchange::VariantValue;
        Sequence<VariantValue> tmp = OrderParamValues (Iterable<String>{L"page", L"xxx"}, PickoutParamValuesFromURL (URI{L"http://www.sophist.com?page=5"}));
        Assert (tmp.size () == 2);
        Assert (tmp[0] == 5);
        Assert (tmp[1] == nullptr);
    }
    // Can declare arguments as Request*,Response*
    static void DefaultPage_ (Request*, Response* response)
    {
        WriteDocsPage (
            response,
            Sequence<WebServiceMethodDescription>{
                kVariables_,
                kPlus_,
                kMinus,
                kTimes,
                kDivide,
            },
            DocsOptions{L"Stroika Sample WebService - Web Methods"_k, L"Note - curl lines all in bash quoting syntax"_k});
    }
    static void SetAppState_ (Message* message)
    {
        String argsAsString = Streams::TextReader::New (message->rwRequest ().GetBody ()).ReadAll ();
        message->rwResponse ().writeln (L"
Hi SetAppState (" + argsAsString.As<wstring> () + L")
");
        message->rwResponse ().contentType = InternetMediaTypes::kHTML;
    }
};

/*
 *  Documentation on WSAPIs
 */
const WebServiceMethodDescription WebServer::Rep_::kVariables_
{
    L"variables"_k,
        Set<String>{HTTP::Methods::kGet, HTTP::Methods::kPost, HTTP::Methods::kDelete},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl http://localhost:8080/variables -v --output -",
            L"curl http://localhost:8080/variables/x -v --output -",
            L"curl  -X POST http://localhost:8080/variables/x -v --output -",
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"value\": 3}' http://localhost:8080/variables/x --output -",
            L"curl -H \"Content-Type: text/plain\" -X POST -d 3 http://localhost:8080/variables/x --output -"},
        Sequence<String>{L"@todo - this is a rough draft (but functional). It could use alot of cleanup and review to see WHICH way I recommend using, and just provide the recommended ways in samples"},
};

const WebServiceMethodDescription WebServer::Rep_::kPlus_
{
    L"plus"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\": 3, \"arg2\": 5 }' http://localhost:8080/plus --output -",
        },
        Sequence<String>{L"add the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kMinus
{
    L"minus"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\": 4.5, \"arg2\": -3.23 }' http://localhost:8080/minus --output -",
        },
        Sequence<String>{L"subtract the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kTimes
{
    L"times"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + 4i\", \"arg2\": 3.2 }' http://localhost:8080/times --output -",
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + i\", \"arg2\": \"2 - i\" }' http://localhost:8080/times --output -",
        },
        Sequence<String>{L"multiply the two argument numbers"},
};
const WebServiceMethodDescription WebServer::Rep_::kDivide
{
    L"divide"_k,
        Set<String>{HTTP::Methods::kPost},
#if qCompilerAndStdLib_static_inline_order_of_construction_Buggy
        InternetMediaType{InternetMediaTypes::Types::kApplication, L"json"sv},
#else
        InternetMediaTypes::kJSON,
#endif
    {},
        Sequence<String>{
            L"curl -H \"Content-Type: application/json\" -X POST -d '{\"arg1\":\"2 + i\", \"arg2\": 0 }' http://localhost:8080/divide --output -",
        },
        Sequence<String>{L"divide the two argument numbers"},
};

WebServer::WebServer (uint16_t portNumber, const shared_ptr<IWSAPI>& wsImpl)
    : fRep_{make_shared<Rep_> (portNumber, wsImpl)}
{
}
<|endoftext|>


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

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "count/empirical_data.h"

namespace {

bool IsDoubleEqual(double a, double b, double epsilon) {
  return (fabs(a - b) < epsilon);
}

}  // namespace

int EstimateDataIncreases() {
  // For our first test, we ensure that the raw estimate tables contain
  // increasing values as the index into each table increases. If this
  // condition did not hold, there would be ambiguity in interpolating
  // a value. For example, in this hypothetical table:
  //
  // [ 2.0, 3.0, 2.5 ]
  //
  // The value at index 2 is less than the value at index 1, which would
  // would imply that for a raw estimoate of 2.75, there are two possible
  // interpolation points.

  // The estimate arrays are terminated by zeroes. Since there are
  // varying numbers of elements in the tables associated with each
  // precision, we must detect the end of the array by comparing its
  // value to zero. We do so using a special floating point comparator
  // defined above, since it is not really safe to compare floats
  // for equality otherwise.
  const double EPSILON = 0.0001;

  // We'll track the number of errors that we encounter and write the
  // errors to standard error. We'll fail the test at the end if the
  // error count is greater than zero.
  size_t error_count = 0;

  // There are a total of fifteen arrays (one for each precision value
  // from precision 4..18 inclusive.
  const size_t TABLE_COUNT = 15;

  // The tables may contain at most 201 usable values. However, the
  // test will compare adjacent elements in the array, and so the loop
  // counter should terminate 1 element earlier.
  const size_t MAX_TABLE_INDEX = 200;

  for (size_t table = 0; table < TABLE_COUNT; ++table) {
    const double* estimates = RAW_ESTIMATE_DATA[table];
    for (size_t index = 0; index < MAX_TABLE_INDEX; ++index) {
      const double lhs = estimates[index];
      const double rhs = estimates[index + 1];
      if (IsDoubleEqual(rhs, 0.0, EPSILON)) {
        // We reached the terminating entry in the table.
        break;
      }

      // Did the lhs, rhs values we're examining violate the condition?
      if (lhs >= rhs) {
        fprintf(stderr,
          "ERROR: lhs >= rhs: In the raw estimate table for precision %lu: \n"
          "  Value at index %lu was: %lf\n"
          "  Value at index %lu was: %lf\n\n",
          table + 4, index, estimates[index], index + 1, estimates[index + 1]);

        ++error_count;
      }
    }
  }

  return (error_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

int main(int argc, char* argv[]) {
  // Values in the raw estimate lookup tables should increase in index order.
  int status = EstimateDataIncreases();
  if (status != EXIT_SUCCESS) {
    return status;
  }
}
<commit_msg>fix cpplint issues<commit_after>// Copyright 2015 The libcount Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. See the AUTHORS file for names of
// contributors.

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "count/empirical_data.h"

namespace {

bool IsDoubleEqual(double a, double b, double epsilon) {
  return (fabs(a - b) < epsilon);
}

}  // namespace

int EstimateDataIncreases() {
  // For our first test, we ensure that the raw estimate tables contain
  // increasing values as the index into each table increases. If this
  // condition did not hold, there would be ambiguity in interpolating
  // a value. For example, in this hypothetical table:
  //
  // [ 2.0, 3.0, 2.5 ]
  //
  // The value at index 2 is less than the value at index 1, which would
  // would imply that for a raw estimoate of 2.75, there are two possible
  // interpolation points.

  // The estimate arrays are terminated by zeroes. Since there are
  // varying numbers of elements in the tables associated with each
  // precision, we must detect the end of the array by comparing its
  // value to zero. We do so using a special floating point comparator
  // defined above, since it is not really safe to compare floats
  // for equality otherwise.
  const double EPSILON = 0.0001;

  // We'll track the number of errors that we encounter and write the
  // errors to standard error. We'll fail the test at the end if the
  // error count is greater than zero.
  size_t error_count = 0;

  // There are a total of fifteen arrays (one for each precision value
  // from precision 4..18 inclusive.
  const size_t TABLE_COUNT = 15;

  // The tables may contain at most 201 usable values. However, the
  // test will compare adjacent elements in the array, and so the loop
  // counter should terminate 1 element earlier.
  const size_t MAX_TABLE_INDEX = 200;

  for (size_t table = 0; table < TABLE_COUNT; ++table) {
    const double* estimates = RAW_ESTIMATE_DATA[table];
    for (size_t index = 0; index < MAX_TABLE_INDEX; ++index) {
      const double lhs = estimates[index];
      const double rhs = estimates[index + 1];
      if (IsDoubleEqual(rhs, 0.0, EPSILON)) {
        // We reached the terminating entry in the table.
        break;
      }

      // Did the lhs, rhs values we're examining violate the condition?
      if (lhs >= rhs) {
        fprintf(
            stderr,
            "ERROR: lhs >= rhs: In the raw estimate table for precision %lu: \n"
            "  Value at index %lu was: %lf\n"
            "  Value at index %lu was: %lf\n\n",
            table + 4, index, estimates[index], index + 1,
            estimates[index + 1]);

        ++error_count;
      }
    }
  }

  return (error_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

int main(int argc, char* argv[]) {
  // Values in the raw estimate lookup tables should increase in index order.
  int status = EstimateDataIncreases();
  if (status != EXIT_SUCCESS) {
    return status;
  }
}
<|endoftext|>


<commit_before>/**
 * @par Licence
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include "VectorOfCities.hpp"

namespace VectorOfCities {

void setDistanceToTheFarthestInTheWholeVector(std::vector<City> &vec) {
    for (City &i : vec) {
        double farthestDistanceSoFar{};
        for (City j : vec) {
            double tmp = i.distanceFrom(j);
            if (tmp > farthestDistanceSoFar) {
                farthestDistanceSoFar = tmp;
            }
        }
        i.setDistanceToTheFarthest(farthestDistanceSoFar);
    }
}

std::size_t getPopulationOfTheWholeVector(const std::vector<City> &vec) {
    std::size_t result{};
    for (const auto &i : vec) {
        result += i.getPopulation();
    }
    return result;
}

std::vector<std::string> regionalize(std::vector<City> vec,
                                     unsigned numberOfRegions) {
    std::vector<std::string> capitals{};
    if (numberOfRegions == 1) {
        capitals = calculateHappinessLevelForOneRegionByBruteForce(vec);
    } else if (numberOfRegions == 2) {
        capitals =
            VectorOfCities::calculateHappinessLevelForTwoRegionsByBruteForce(
                vec);
    } else {
        capitals = VectorOfCities::regionalizeUsingRandom(vec, numberOfRegions);
    }
    GnuplotHandler::plotHappinessIndex(vec, capitals);
    return capitals;
}

std::vector<std::string>
calculateHappinessLevelForOneRegionByBruteForce(std::vector<City> vec) {
    std::vector<std::string> bestCapitalSoFar{};
    std::size_t bestHLsoFar{};
    for (City i : vec) {
        // std::cout << " " << i.getName() << "\t";
        std::size_t hl{}; // happiness level
        for (City j : vec) {
            std::size_t tmp =
                (10.0 - ((static_cast<double>(j.distanceFrom(i)) /
                          static_cast<double>(j.getDistanceToTheFarthest())) *
                         10.0));
            hl += (j.getPopulation() * tmp);
        }
        // std::cout << "Happiness level = " << hl;
        // std::cout << std::endl;
        if (hl > bestHLsoFar) {
            bestHLsoFar = hl;
            bestCapitalSoFar.clear();
            bestCapitalSoFar.push_back(i.getName());
        }
    }
    std::cout << std::endl;
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalSoFar;
}

std::vector<std::string>
calculateHappinessLevelForTwoRegionsByBruteForce(const std::vector<City> &vec) {
    std::vector<std::string> bestCapitalsSoFar{};
    std::size_t bestHLsoFar{};
    auto sortedVec = sortVec(vec);
    auto it = sortedVec.begin();
    auto jt = it;
    for (; it != sortedVec.begin() + 8; ++it) {
        for (jt = it + 1; jt != sortedVec.begin() + 9; ++jt) {
            // std::cout << it->getName() << " " << jt->getName() << "\n";
            std::size_t hl{};
            for (const auto &i : sortedVec) {
                std::size_t distanceToit = i.distanceFrom(*it);
                std::size_t distanceTojt = i.distanceFrom(*jt);
                std::size_t distanceToTheClosestCapital =
                    distanceToit > distanceTojt ? distanceTojt : distanceToit;
                std::size_t tmp =
                    (10.0 -
                     ((static_cast<double>(distanceToTheClosestCapital) /
                       static_cast<double>(i.getDistanceToTheFarthest())) *
                      10.0));
                hl += (i.getPopulation() * tmp);
            }
            // std::cout << "Happiness level = " << hl;
            // std::cout << std::endl;
            if (hl > bestHLsoFar) {
                bestHLsoFar = hl;
                bestCapitalsSoFar.clear();
                bestCapitalsSoFar.push_back(it->getName());
                bestCapitalsSoFar.push_back(jt->getName());
            }
        }
    }
    std::cout << std::endl;
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalsSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalsSoFar;
}

std::vector<unsigned> generateRandomVectorWithoutRepetition(unsigned floor,
                                                            unsigned ceil,
                                                            unsigned size) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(floor, ceil);

    std::vector<unsigned> vecOfRand;
    vecOfRand.reserve(size);
    vecOfRand.push_back(dis(gen));
    while (vecOfRand.size() < size) {
        unsigned tmp = dis(gen);
        if (std::find(vecOfRand.begin(), vecOfRand.end(), tmp) ==
            vecOfRand.end()) {
            vecOfRand.push_back(tmp);
        }
    }
    return vecOfRand;
}

std::vector<std::string> regionalizeUsingRandom(std::vector<City> vec,
                                                std::string numberOfRegions) {
    return regionalizeUsingRandom(vec, std::stoi(numberOfRegions));
}

std::vector<std::string> regionalizeUsingRandom(std::vector<City> vec,
                                                unsigned numberOfRegions) {
    std::cout << "regionalizeUsingRandom \n";
    std::cout << "number of regions = " << numberOfRegions << "\n";

    constexpr std::size_t tries{100};
    std::vector<std::string> bestCapitalsSoFar{};
    std::size_t bestHLsoFar{};
    auto sortedVec = sortVec(vec);

    for (std::size_t i{}; i < tries; ++i) {
        auto vecOfRand = generateRandomVectorWithoutRepetition(
            1, sortedVec.size(), numberOfRegions);
        //      for (auto j : vecOfRand) { std::cout << j << "-";} std::cout <<
        //      "\n";
        std::size_t hl{};
        for (City j : sortedVec) {
            std::size_t bestTmpSoFar{};
            for (auto x : vecOfRand) {
                std::size_t tmp =
                    (10.0 -
                     ((static_cast<double>(j.distanceFrom(sortedVec[x])) /
                       static_cast<double>(j.getDistanceToTheFarthest())) *
                      10.0));
                if (tmp > bestTmpSoFar) {
                    bestTmpSoFar = tmp;
                }
            }
            hl += (j.getPopulation() * bestTmpSoFar);
        }
        if (hl > bestHLsoFar) {
            bestHLsoFar = hl;
            bestCapitalsSoFar.clear();
            for (auto it = vecOfRand.begin(); it != vecOfRand.end(); ++it) {
                bestCapitalsSoFar.push_back(sortedVec[*it].getName());
            }
        }
    }
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalsSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalsSoFar;
}

std::vector<City> sortVec(const std::vector<City> &vec) {
    auto sortedVec = vec;
    sort(sortedVec.begin(), sortedVec.end(),
         [](const City &lhs, const City &rhs) {
             return lhs.getPopulation() > rhs.getPopulation();
         });
    return sortedVec;
}

} // namespace VectorOfCities
<commit_msg>Fix for out-of-bounds error in regionalize<commit_after>/**
 * @par Licence
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include "VectorOfCities.hpp"

namespace VectorOfCities {

void setDistanceToTheFarthestInTheWholeVector(std::vector<City> &vec) {
    for (City &i : vec) {
        double farthestDistanceSoFar{};
        for (City j : vec) {
            double tmp = i.distanceFrom(j);
            if (tmp > farthestDistanceSoFar) {
                farthestDistanceSoFar = tmp;
            }
        }
        i.setDistanceToTheFarthest(farthestDistanceSoFar);
    }
}

std::size_t getPopulationOfTheWholeVector(const std::vector<City> &vec) {
    std::size_t result{};
    for (const auto &i : vec) {
        result += i.getPopulation();
    }
    return result;
}

std::vector<std::string> regionalize(std::vector<City> vec,
                                     unsigned numberOfRegions) {
    std::vector<std::string> capitals{};
    if (numberOfRegions == 1) {
        capitals = calculateHappinessLevelForOneRegionByBruteForce(vec);
    } else if (numberOfRegions == 2) {
        capitals =
            VectorOfCities::calculateHappinessLevelForTwoRegionsByBruteForce(
                vec);
    } else {
        capitals = VectorOfCities::regionalizeUsingRandom(vec, numberOfRegions);
    }
    GnuplotHandler::plotHappinessIndex(vec, capitals);
    return capitals;
}

std::vector<std::string>
calculateHappinessLevelForOneRegionByBruteForce(std::vector<City> vec) {
    std::vector<std::string> bestCapitalSoFar{};
    std::size_t bestHLsoFar{};
    for (City i : vec) {
        // std::cout << " " << i.getName() << "\t";
        std::size_t hl{}; // happiness level
        for (City j : vec) {
            std::size_t tmp =
                (10.0 - ((static_cast<double>(j.distanceFrom(i)) /
                          static_cast<double>(j.getDistanceToTheFarthest())) *
                         10.0));
            hl += (j.getPopulation() * tmp);
        }
        // std::cout << "Happiness level = " << hl;
        // std::cout << std::endl;
        if (hl > bestHLsoFar) {
            bestHLsoFar = hl;
            bestCapitalSoFar.clear();
            bestCapitalSoFar.push_back(i.getName());
        }
    }
    std::cout << std::endl;
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalSoFar;
}

std::vector<std::string>
calculateHappinessLevelForTwoRegionsByBruteForce(const std::vector<City> &vec) {
    std::vector<std::string> bestCapitalsSoFar{};
    std::size_t bestHLsoFar{};
    auto sortedVec = sortVec(vec);
    auto it = sortedVec.begin();
    auto jt = it;
    for (; it != sortedVec.begin() + 8; ++it) {
        for (jt = it + 1; jt != sortedVec.begin() + 9; ++jt) {
            // std::cout << it->getName() << " " << jt->getName() << "\n";
            std::size_t hl{};
            for (const auto &i : sortedVec) {
                std::size_t distanceToit = i.distanceFrom(*it);
                std::size_t distanceTojt = i.distanceFrom(*jt);
                std::size_t distanceToTheClosestCapital =
                    distanceToit > distanceTojt ? distanceTojt : distanceToit;
                std::size_t tmp =
                    (10.0 -
                     ((static_cast<double>(distanceToTheClosestCapital) /
                       static_cast<double>(i.getDistanceToTheFarthest())) *
                      10.0));
                hl += (i.getPopulation() * tmp);
            }
            // std::cout << "Happiness level = " << hl;
            // std::cout << std::endl;
            if (hl > bestHLsoFar) {
                bestHLsoFar = hl;
                bestCapitalsSoFar.clear();
                bestCapitalsSoFar.push_back(it->getName());
                bestCapitalsSoFar.push_back(jt->getName());
            }
        }
    }
    std::cout << std::endl;
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalsSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalsSoFar;
}

std::vector<unsigned> generateRandomVectorWithoutRepetition(unsigned floor,
                                                            unsigned ceil,
                                                            unsigned size) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(floor, ceil);

    std::vector<unsigned> vecOfRand;
    vecOfRand.reserve(size);
    vecOfRand.push_back(dis(gen));
    while (vecOfRand.size() < size) {
        unsigned tmp = dis(gen);
        if (std::find(vecOfRand.begin(), vecOfRand.end(), tmp) ==
            vecOfRand.end()) {
            vecOfRand.push_back(tmp);
        }
    }
    return vecOfRand;
}

std::vector<std::string> regionalizeUsingRandom(std::vector<City> vec,
                                                std::string numberOfRegions) {
    return regionalizeUsingRandom(vec, std::stoi(numberOfRegions));
}

std::vector<std::string> regionalizeUsingRandom(std::vector<City> vec,
                                                unsigned numberOfRegions) {
    std::cout << "regionalizeUsingRandom \n";
    std::cout << "number of regions = " << numberOfRegions << "\n";

    constexpr std::size_t tries{100};
    std::vector<std::string> bestCapitalsSoFar{};
    std::size_t bestHLsoFar{};
    auto sortedVec = sortVec(vec);

    for (std::size_t i{}; i < tries; ++i) {
        auto vecOfRand = generateRandomVectorWithoutRepetition(
            0, sortedVec.size()-1, numberOfRegions);
        //      for (auto j : vecOfRand) { std::cout << j << "-";} std::cout <<
        //      "\n";
        std::size_t hl{};
        for (City j : sortedVec) {
            std::size_t bestTmpSoFar{};
            for (auto x : vecOfRand) {
                std::size_t tmp =
                    (10.0 -
                     ((static_cast<double>(j.distanceFrom(sortedVec[x])) /
                       static_cast<double>(j.getDistanceToTheFarthest())) *
                      10.0));
                if (tmp > bestTmpSoFar) {
                    bestTmpSoFar = tmp;
                }
            }
            hl += (j.getPopulation() * bestTmpSoFar);
        }
        if (hl > bestHLsoFar) {
            bestHLsoFar = hl;
            bestCapitalsSoFar.clear();
            for (auto it = vecOfRand.begin(); it != vecOfRand.end(); ++it) {
                bestCapitalsSoFar.push_back(sortedVec[*it].getName());
            }
        }
    }
    std::cout << "The best capitals would be ";
    for (auto i : bestCapitalsSoFar) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "Happiness level = " << bestHLsoFar;
    std::cout << std::endl;
    std::cout << "Population = " << getPopulationOfTheWholeVector(vec);
    std::cout << std::endl;
    std::cout << "Percentage = "
              << static_cast<double>(10.0 * bestHLsoFar) /
                     getPopulationOfTheWholeVector(vec)
              << "%";
    std::cout << std::endl;

    return bestCapitalsSoFar;
}

std::vector<City> sortVec(const std::vector<City> &vec) {
    auto sortedVec = vec;
    sort(sortedVec.begin(), sortedVec.end(),
         [](const City &lhs, const City &rhs) {
             return lhs.getPopulation() > rhs.getPopulation();
         });
    return sortedVec;
}

} // namespace VectorOfCities
<|endoftext|>


<commit_before><commit_msg>:construction: chore(common): updated the common module<commit_after><|endoftext|>


<commit_before>// Source: http://www.daniweb.com/software-development/cpp/code/427500/calculator-using-shunting-yard-algorithm#
// Author: Jesse Brown
// Modifications: Brandon Amos, redpois0n

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <math.h>

#include "shunting-yard.h"

std::map<std::string, int> calculator::buildOpPrecedence() {
  std::map<std::string, int> opp;

  // Create the operator precedence map based on C++ default
  // precedence order as described on cppreference website:
  // http://en.cppreference.com/w/c/language/operator_precedence
  opp["^"]  = 2;
  opp["*"]  = 3; opp["/"]  = 3; opp["%"] = 3;
  opp["+"]  = 4; opp["-"]  = 4;
  opp["<<"] = 5; opp[">>"] = 5;
  opp["<"]  = 6; opp["<="] = 6; opp[">="] = 6; opp[">"] = 6;
  opp["=="] = 7; opp["!="] = 7;
  opp["&&"] = 11;
  opp["||"] = 12;
  opp["("]  = 16;

  return opp;
}
// Builds the opPrecedence map only once:
std::map<std::string, int> calculator::opPrecedence = calculator::buildOpPrecedence();

#define isvariablechar(c) (isalpha(c) || c == '_')
TokenQueue_t calculator::toRPN(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {
  TokenQueue_t rpnQueue; std::stack<std::string> operatorStack;
  bool lastTokenWasOp = true;

  // In one pass, ignore whitespace and parse the expression into RPN
  // using Dijkstra's Shunting-yard algorithm.
  while (*expr && isspace(*expr )) ++expr;
  while (*expr ) {
    if (isdigit(*expr )) {
      // If the token is a number, add it to the output queue.
      char* nextChar = 0;
      double digit = strtod(expr , &nextChar);
#     ifdef DEBUG
        std::cout << digit << std::endl;
#     endif
      rpnQueue.push(new Token<double>(digit, NUM));
      expr = nextChar;
      lastTokenWasOp = false;
    } else if (isvariablechar(*expr )) {
      // If the function is a variable, resolve it and
      // add the parsed number to the output queue.
      std::stringstream ss;
      ss << *expr;
      ++expr;
      while( isvariablechar(*expr ) || isdigit(*expr) ) {
        ss << *expr;
        ++expr;
      }

      bool found = false;
      double val;

      std::string key = ss.str();

      if(key == "true") {
        found = true; val = 1;
      } else if(key == "false") {
        found = true; val = 0;
      } else if(vars) {
        std::map<std::string, double>::iterator it = vars->find(key);
        if(it != vars->end()) { found = true; val = it->second; }
      }

      if (found) {
        // Save the number
  #     ifdef DEBUG
          std::cout << val << std::endl;
  #     endif
        rpnQueue.push(new Token<double>(val, NUM));;
      } else {
        // Save the variable name:
  #     ifdef DEBUG
          std::cout << key << std::endl;
  #     endif
        rpnQueue.push(new Token<std::string>(key, VAR));
      }

      lastTokenWasOp = false;
    } else {
      // Otherwise, the variable is an operator or paranthesis.
      switch (*expr) {
        case '(':
          operatorStack.push("(");
          ++expr;
          break;
        case ')':
          while (operatorStack.top().compare("(")) {
            rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
            operatorStack.pop();
          }
          operatorStack.pop();
          ++expr;
          break;
        default:
          {
            // The token is an operator.
            //
            // Let p(o) denote the precedence of an operator o.
            //
            // If the token is an operator, o1, then
            //   While there is an operator token, o2, at the top
            //       and p(o1) <= p(o2), then
            //     pop o2 off the stack onto the output queue.
            //   Push o1 on the stack.
            std::stringstream ss;
            ss << *expr;
            ++expr;
            while (*expr && !isspace(*expr ) && !isdigit(*expr )
                && !isvariablechar(*expr) && *expr != '(' && *expr != ')') {
              ss << *expr;
              ++expr;
            }
            ss.clear();
            std::string str;
            ss >> str;
#           ifdef DEBUG
              std::cout << str << std::endl;
#           endif

            if (lastTokenWasOp) {
              // Convert unary operators to binary in the RPN.
              if (!str.compare("-") || !str.compare("+")) {
                rpnQueue.push(new Token<double>(0, NUM));
              } else {
                throw std::domain_error(
                    "Unrecognized unary operator: '" + str + "'.");
              }
            }

            while (!operatorStack.empty() &&
                opPrecedence[str] >= opPrecedence[operatorStack.top()]) {
              rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
              operatorStack.pop();
            }
            operatorStack.push(str);
            lastTokenWasOp = true;
          }
      }
    }
    while (*expr && isspace(*expr )) ++expr;
  }
  while (!operatorStack.empty()) {
    rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
    operatorStack.pop();
  }
  return rpnQueue;
}

double calculator::calculate(const char* expr,
    std::map<std::string, double>* vars) {

  // Convert to RPN with Dijkstra's Shunting-yard algorithm.
  TokenQueue_t rpn = toRPN(expr, vars);

  double ret = calculate(rpn);

  cleanRPN(rpn);

  return ret;
}

double calculator::calculate(TokenQueue_t rpn,
    std::map<std::string, double>* vars) {

  // Evaluate the expression in RPN form.
  std::stack<double> evaluation;
  while (!rpn.empty()) {
    TokenBase* base = rpn.front();
    rpn.pop();

    // Operator:
    if (base->type == OP) {
      Token<std::string>* strTok = static_cast<Token<std::string>*>(base);
      std::string str = strTok->val;
      if (evaluation.size() < 2) {
        throw std::domain_error("Invalid equation.");
      }
      double right = evaluation.top(); evaluation.pop();
      double left  = evaluation.top(); evaluation.pop();
      if (!str.compare("+")) {
        evaluation.push(left + right);
      } else if (!str.compare("*")) {
        evaluation.push(left * right);
      } else if (!str.compare("-")) {
        evaluation.push(left - right);
      } else if (!str.compare("/")) {
        evaluation.push(left / right);
      } else if (!str.compare("<<")) {
        evaluation.push((int) left << (int) right);
      } else if (!str.compare("^")) {
        evaluation.push(pow(left, right));
      } else if (!str.compare(">>")) {
        evaluation.push((int) left >> (int) right);
      } else if (!str.compare("%")) {
        evaluation.push((int) left % (int) right);
      } else if (!str.compare("<")) {
        evaluation.push(left < right);
      } else if (!str.compare(">")) {
        evaluation.push(left > right);
      } else if (!str.compare("<=")) {
        evaluation.push(left <= right);
      } else if (!str.compare(">=")) {
        evaluation.push(left >= right);
      } else if (!str.compare("==")) {
        evaluation.push(left == right);
      } else if (!str.compare("!=")) {
        evaluation.push(left != right);
      } else if (!str.compare("&&")) {
        evaluation.push((int) left && (int) right);
      } else if (!str.compare("||")) {
        evaluation.push((int) left || (int) right);
      } else {
        throw std::domain_error("Unknown operator: '" + str + "'.");
      }
    } else if (base->type == NUM) { // Number
      Token<double>* doubleTok = static_cast<Token<double>*>(base);
      evaluation.push(doubleTok->val);
    } else if (base->type == VAR) { // Variable
      if (!vars) {
        throw std::domain_error(
            "Detected variable, but the variable map is null.");
      }

      Token<std::string>* strTok = static_cast<Token<std::string>*>(base);

      std::string key = strTok->val;
      std::map<std::string, double>::iterator it = vars->find(key);

      if (it == vars->end()) {
        throw std::domain_error(
            "Unable to find the variable '" + key + "'.");
      }
      evaluation.push(it->second);
    } else {
      throw std::domain_error("Invalid token.");
    }
  }
  return evaluation.top();
}

void calculator::cleanRPN(TokenQueue_t& rpn) {
  while( rpn.size() ) {
    delete rpn.front();
    rpn.pop();
  }
}

/* * * * * Non Static Functions * * * * */

calculator::~calculator() {
  cleanRPN(this->RPN);
}

calculator::calculator(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {
  compile(expr, vars, opPrecedence);
}

void calculator::compile(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {

  // Make sure it is empty:
  cleanRPN(this->RPN);

  this->RPN = calculator::toRPN(expr, vars, opPrecedence);
}

double calculator::eval(std::map<std::string, double>* vars) {
  return calculate(this->RPN, vars);
}

/* * * * * For Debug Only * * * * */

std::string calculator::str() {
  std::stringstream ss;
  TokenQueue_t rpn = this->RPN;

  ss << "calculator { RPN: [ ";
  while( rpn.size() ) {
    TokenBase* base = rpn.front();

    Token<double>* doubleTok = dynamic_cast<Token<double>*>(base);
    if(doubleTok)
      ss << doubleTok->val;

    Token<std::string>* strTok = dynamic_cast<Token<std::string>*>(base);
    if(strTok)
      ss << "'" << strTok->val << "'";

    rpn.pop();

    ss << (rpn.size() ? ", ":"");
  }
  ss << " ] }";
  return ss.str();
}
<commit_msg>Added shunting yard code<commit_after>// Source: http://www.daniweb.com/software-development/cpp/code/427500/calculator-using-shunting-yard-algorithm#
// Author: Jesse Brown
// Modifications: Brandon Amos, redpois0n

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <math.h>

#include "shunting-yard.h"

std::map<std::string, int> calculator::buildOpPrecedence() {
  std::map<std::string, int> opp;

  // Create the operator precedence map based on C++ default
  // precedence order as described on cppreference website:
  // http://en.cppreference.com/w/c/language/operator_precedence
  opp["^"]  = 2;
  opp["*"]  = 3; opp["/"]  = 3; opp["%"] = 3;
  opp["+"]  = 4; opp["-"]  = 4;
  opp["<<"] = 5; opp[">>"] = 5;
  opp["<"]  = 6; opp["<="] = 6; opp[">="] = 6; opp[">"] = 6;
  opp["=="] = 7; opp["!="] = 7;
  opp["&&"] = 11;
  opp["||"] = 12;
  opp["("]  = 16;

  return opp;
}
// Builds the opPrecedence map only once:
std::map<std::string, int> calculator::opPrecedence = calculator::buildOpPrecedence();

#define isvariablechar(c) (isalpha(c) || c == '_')
TokenQueue_t calculator::toRPN(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {
  TokenQueue_t rpnQueue; std::stack<std::string> operatorStack;
  bool lastTokenWasOp = true;

  // In one pass, ignore whitespace and parse the expression into RPN
  // using Dijkstra's Shunting-yard algorithm.
  while (*expr && isspace(*expr )) ++expr;
  while (*expr ) {
    if (isdigit(*expr )) {
      // If the token is a number, add it to the output queue.
      char* nextChar = 0;
      double digit = strtod(expr , &nextChar);
#     ifdef DEBUG
        std::cout << digit << std::endl;
#     endif
      rpnQueue.push(new Token<double>(digit, NUM));
      expr = nextChar;
      lastTokenWasOp = false;
    } else if (isvariablechar(*expr )) {
      // If the function is a variable, resolve it and
      // add the parsed number to the output queue.
      std::stringstream ss;
      ss << *expr;
      ++expr;
      while( isvariablechar(*expr ) || isdigit(*expr) ) {
        ss << *expr;
        ++expr;
      }

      bool found = false;
      double val;

      std::string key = ss.str();

      if(key == "true") {
        found = true; val = 1;
      } else if(key == "false") {
        found = true; val = 0;
      } else if(vars) {
        std::map<std::string, double>::iterator it = vars->find(key);
        if(it != vars->end()) { found = true; val = it->second; }
      }

      if (found) {
        // Save the number
  #     ifdef DEBUG
          std::cout << val << std::endl;
  #     endif
        rpnQueue.push(new Token<double>(val, NUM));;
      } else {
        // Save the variable name:
  #     ifdef DEBUG
          std::cout << key << std::endl;
  #     endif
        rpnQueue.push(new Token<std::string>(key, VAR));
      }

      lastTokenWasOp = false;
    } else {
      // Otherwise, the variable is an operator or paranthesis.
      switch (*expr) {
        case '(':
          operatorStack.push("(");
          ++expr;
          break;
        case ')':
          while (operatorStack.top().compare("(")) {
            rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
            operatorStack.pop();
          }
          operatorStack.pop();
          ++expr;
          break;
        default:
          {
            // The token is an operator.
            //
            // Let p(o) denote the precedence of an operator o.
            //
            // If the token is an operator, o1, then
            //   While there is an operator token, o2, at the top
            //       and p(o1) <= p(o2), then
            //     pop o2 off the stack onto the output queue.
            //   Push o1 on the stack.
            std::stringstream ss;
            ss << *expr;
            ++expr;
            while (*expr && !isspace(*expr ) && !isdigit(*expr )
                && !isvariablechar(*expr) && *expr != '(' && *expr != ')') {
              ss << *expr;
              ++expr;
            }
            ss.clear();
            std::string str;
            ss >> str;
#           ifdef DEBUG
              std::cout << str << std::endl;
#           endif

            if (lastTokenWasOp) {
              // Convert unary operators to binary in the RPN.
              if (!str.compare("-") || !str.compare("+")) {
                rpnQueue.push(new Token<double>(0, NUM));
              } else {
                throw std::domain_error(
                    "Unrecognized unary operator: '" + str + "'.");
              }
            }

            while (!operatorStack.empty() &&
                opPrecedence[str] >= opPrecedence[operatorStack.top()]) {
              rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
              operatorStack.pop();
            }
            operatorStack.push(str);
            lastTokenWasOp = true;
          }
      }
    }
    while (*expr && isspace(*expr )) ++expr;
  }
  while (!operatorStack.empty()) {
    rpnQueue.push(new Token<std::string>(operatorStack.top(), OP));
    operatorStack.pop();
  }
  return rpnQueue;
}

double calculator::calculate(const char* expr,
    std::map<std::string, double>* vars) {

  // Convert to RPN with Dijkstra's Shunting-yard algorithm.
  TokenQueue_t rpn = toRPN(expr, vars);

  double ret = calculate(rpn);

  cleanRPN(rpn);

  return ret;
}

double calculator::calculate(TokenQueue_t rpn,
    std::map<std::string, double>* vars) {

  // Evaluate the expression in RPN form.
  std::stack<double> evaluation;
  while (!rpn.empty()) {
    TokenBase* base = rpn.front();
    rpn.pop();

    // Operator:
    if (base->type == OP) {
      Token<std::string>* strTok = static_cast<Token<std::string>*>(base);
      std::string str = strTok->val;
      if (evaluation.size() < 2) {
        throw std::domain_error("Invalid equation.");
      }
      double right = evaluation.top(); evaluation.pop();
      double left  = evaluation.top(); evaluation.pop();
            if (!str.compare("+")) {
        evaluation.push(ml_add(left,right));
      } else if (!str.compare("*")) {
        evaluation.push(ml_mul(left,right));
      } else if (!str.compare("-")) {
        evaluation.push(ml_sub(left,right));
      } else if (!str.compare("/")) {
        evaluation.push(ml_div(left,right));
      } else if (!str.compare("<<")) {
        evaluation.push((int) left << (int) right);
      } else if (!str.compare("^")) {
        evaluation.push(ml_power(left,right));
      } else if (!str.compare(">>")) {
        evaluation.push((int) left >> (int) right);
      } else if (!str.compare("%")) {
        evaluation.push(ml_mod(left,right));
      } else if (!str.compare("<")) {
        evaluation.push(left < right);
      } else if (!str.compare(">")) {
        evaluation.push(left > right);
      } else if (!str.compare("<=")) {
        evaluation.push(left <= right);
      } else if (!str.compare(">=")) {
        evaluation.push(left >= right);
      } else if (!str.compare("==")) {
        evaluation.push(left == right);
      } else if (!str.compare("!=")) {
        evaluation.push(left != right);
      } else if (!str.compare("&&")) {
        evaluation.push((int) left && (int) right);
      } else if (!str.compare("||")) {
        evaluation.push((int) left || (int) right);
      } else {
        throw std::domain_error("Unknown operator: '" + str + "'.");
      }
    } else if (base->type == NUM) { // Number
      Token<double>* doubleTok = static_cast<Token<double>*>(base);
      evaluation.push(doubleTok->val);
    } else if (base->type == VAR) { // Variable
      if (!vars) {
        throw std::domain_error(
            "Detected variable, but the variable map is null.");
      }

      Token<std::string>* strTok = static_cast<Token<std::string>*>(base);

      std::string key = strTok->val;
      std::map<std::string, double>::iterator it = vars->find(key);

      if (it == vars->end()) {
        throw std::domain_error(
            "Unable to find the variable '" + key + "'.");
      }
      evaluation.push(it->second);
    } else {
      throw std::domain_error("Invalid token.");
    }
  }
  return evaluation.top();
}

void calculator::cleanRPN(TokenQueue_t& rpn) {
  while( rpn.size() ) {
    delete rpn.front();
    rpn.pop();
  }
}

/* * * * * Non Static Functions * * * * */

calculator::~calculator() {
  cleanRPN(this->RPN);
}

calculator::calculator(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {
  compile(expr, vars, opPrecedence);
}

void calculator::compile(const char* expr,
    std::map<std::string, double>* vars,
    std::map<std::string, int> opPrecedence) {

  // Make sure it is empty:
  cleanRPN(this->RPN);

  this->RPN = calculator::toRPN(expr, vars, opPrecedence);
}

double calculator::eval(std::map<std::string, double>* vars) {
  return calculate(this->RPN, vars);
}

/* * * * * For Debug Only * * * * */

std::string calculator::str() {
  std::stringstream ss;
  TokenQueue_t rpn = this->RPN;

  ss << "calculator { RPN: [ ";
  while( rpn.size() ) {
    TokenBase* base = rpn.front();

    Token<double>* doubleTok = dynamic_cast<Token<double>*>(base);
    if(doubleTok)
      ss << doubleTok->val;

    Token<std::string>* strTok = dynamic_cast<Token<std::string>*>(base);
    if(strTok)
      ss << "'" << strTok->val << "'";

    rpn.pop();

    ss << (rpn.size() ? ", ":"");
  }
  ss << " ] }";
  return ss.str();
}
<|endoftext|>


<commit_before>#include "config.h"
#include "util/libevent_wrapper.h"

#include <arpa/inet.h>
#ifdef HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h> /* DNS HEADER struct */
#endif
#include <event2/keyvalq_struct.h>
#include <event2/thread.h>
#include <evhtp.h>
#include <glog/logging.h>
#include <math.h>
#include <climits>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <netdb.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* inet_ functions / structs */
#endif
#include <resolv.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <signal.h>

using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::chrono::system_clock;
using std::function;
using std::lock_guard;
using std::make_pair;
using std::multimap;
using std::mutex;
using std::placeholders::_1;
using std::recursive_mutex;
using std::shared_ptr;
using std::string;
using std::unique_ptr;
using std::vector;
using util::TaskHold;

namespace {

void FreeEvDns(evdns_base* dns) {
  if (dns) {
    evdns_base_free(dns, true);
  }
}

static void Handler_ExitLoop(evutil_socket_t, short, void* base) {
  event_base_loopexit((event_base*)base, NULL);
}

void SetExitLoopHandler(event_base* base, int signum) {
  struct event* signal_event;
  // TODO(pphaneuf): this should be free'd
  signal_event = evsignal_new(base, signum, Handler_ExitLoop, base);
  CHECK_NOTNULL(signal_event);
  CHECK_GE(event_add(signal_event, NULL), 0);
}

void DelayCancel(event* timer, util::Task* task) {
  event_del(timer);
  task->Return(util::Status::CANCELLED);
}

void DelayDispatch(evutil_socket_t, short, void* userdata) {
  static_cast<util::Task*>(CHECK_NOTNULL(userdata))->Return();
}

#ifdef HAVE_THREAD_LOCAL
thread_local bool on_event_thread = false;
#elif HAVE___THREAD
__thread bool on_event_thread = false;
#else
#error No suitable thread local storage available
#endif

}  // namespace

namespace cert_trans {
namespace libevent {

struct HttpServer::Handler {
  Handler(const string& _path, const HandlerCallback& _cb)
      : path(_path), cb(_cb) {
  }

  const string path;
  const HandlerCallback cb;
};

class ResolverImpl : public Base::Resolver {
 public:
  string Resolve(const string& host) override {
    struct addrinfo* info;
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    // It seems evhtp doesn't support IPv6 addresses because it uses
    // inet_addr() to parse the passed in "stringified" address.
    // Restrict to IPv4 addresses for now:
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    const int resolved(getaddrinfo(host.c_str(), AF_UNSPEC, &hints, &info));
    if (resolved != 0) {
      LOG(WARNING) << "Failed to resolve HTTPS hostname " << host << ": "
                   << gai_strerror(resolved);
      return nullptr;
    }

    struct addrinfo* res(info);
    void* addr(nullptr);
    while (res && !addr) {
      switch (res->ai_family) {
        case AF_INET:
          addr =
              &reinterpret_cast<struct sockaddr_in*>(res->ai_addr)->sin_addr;
          break;
        case AF_INET6:
          // Just in case one day evhtp uses inet_pton()
          addr =
              &reinterpret_cast<struct sockaddr_in6*>(res->ai_addr)->sin6_addr;
          break;
        default:
          res = res->ai_next;
          break;
      }
    }

    if (!addr) {
      LOG(WARNING) << "Got no usable address for " << host;
      return nullptr;
    }

    char addr_str[INET6_ADDRSTRLEN];
    inet_ntop(res->ai_family, addr, addr_str, INET6_ADDRSTRLEN);
    freeaddrinfo(info);
    return string(addr_str);
  }
};

Base::Base() : Base(unique_ptr<Resolver>(new ResolverImpl)) {
}

Base::Base(unique_ptr<Resolver> resolver)
    : base_(CHECK_NOTNULL(event_base_new()), event_base_free),
      dns_(nullptr, FreeEvDns),
      wake_closures_(event_new(base_.get(), -1, 0, &Base::RunClosures, this),
                     &event_free),
      resolver_(std::move(resolver)) {
  evthread_make_base_notifiable(base_.get());

  // So much stuff breaks if there's not a Dns client around to keep the
  // event loop doing stuff that we may as well just have one from the get go.
  GetDns();
}

Base::~Base() {
}

// static
bool Base::OnEventThread() {
  return on_event_thread;
}

// static
void Base::CheckNotOnEventThread() {
  CHECK_EQ(false, OnEventThread());
}

void Base::Add(const function<void()>& cb) {
  lock_guard<mutex> lock(closures_lock_);
  closures_.push_back(cb);
  event_active(wake_closures_.get(), 0, 0);
}

void Base::Delay(const duration<double>& delay, util::Task* task) {
  // If the delay is zero (or less?), what the heck, we're done!
  if (delay <= delay.zero()) {
    task->Return();
    return;
  }

  // Make sure nothing "bad" happens while we're still setting up our
  // callbacks.
  TaskHold hold(task);

  event* timer(CHECK_NOTNULL(evtimer_new(base_.get(), &DelayDispatch, task)));

  // Ensure that the cancellation callback is run on this libevent::Base, to
  // avoid races during cancellation.

  // Cancellation callbacks are always called before the task enters
  // the DONE state (and "timer" is freed), and "event_del" is
  // thread-safe, so it does not matter on which thread "DelayCancel"
  // is called on.
  task->WhenCancelled(bind(DelayCancel, timer, task));

  task->CleanupWhenDone(bind(event_free, timer));

  timeval tv;
  const seconds sec(duration_cast<seconds>(delay));
  tv.tv_sec = sec.count();
  tv.tv_usec = duration_cast<microseconds>(delay - sec).count();

  CHECK_EQ(evtimer_add(timer, &tv), 0);
}

void Base::Dispatch() {
  SetExitLoopHandler(base_.get(), SIGHUP);
  SetExitLoopHandler(base_.get(), SIGINT);
  SetExitLoopHandler(base_.get(), SIGTERM);

  // There should /never/ be more than 1 thread trying to call Dispatch(), so
  // we should expect to always own the lock here.
  CHECK(dispatch_lock_.try_lock());
  LOG_IF(WARNING, on_event_thread)
      << "Huh?, Are you calling Dispatch() from a libevent thread?";
  const bool old_on_event_thread(on_event_thread);
  on_event_thread = true;
  CHECK_EQ(event_base_dispatch(base_.get()), 0);
  on_event_thread = old_on_event_thread;
  dispatch_lock_.unlock();
}

void Base::DispatchOnce() {
  // Only one thread can be running a dispatch loop at a time
  lock_guard<mutex> lock(dispatch_lock_);
  LOG_IF(WARNING, on_event_thread)
      << "Huh?, Are you calling Dispatch() from a libevent thread?";
  const bool old_on_event_thread(on_event_thread);
  on_event_thread = true;
  CHECK_EQ(event_base_loop(base_.get(), EVLOOP_ONCE), 0);
  on_event_thread = old_on_event_thread;
}

void Base::LoopExit() {
  event_base_loopexit(base_.get(), nullptr);
}

event* Base::EventNew(evutil_socket_t& sock, short events,
                      Event* event) const {
  return CHECK_NOTNULL(
      event_new(base_.get(), sock, events, &Event::Dispatch, event));
}

evhttp* Base::HttpNew() const {
  const ev_ssize_t max_http_header_size = 4096;
  const ev_ssize_t max_http_post_body_size = 32768;
  evhttp* http_session = CHECK_NOTNULL(evhttp_new(base_.get()));
  evhttp_set_max_headers_size(http_session, max_http_header_size);
  evhttp_set_max_body_size(http_session, max_http_post_body_size);
  return http_session;
}

evdns_base* Base::GetDns() {
  lock_guard<mutex> lock(dns_lock_);

  if (!dns_) {
    dns_.reset(CHECK_NOTNULL(evdns_base_new(base_.get(), 1)));
  }

  return dns_.get();
}

evhtp_connection_t* Base::HttpConnectionNew(const string& host,
                                            unsigned short port) {
  return CHECK_NOTNULL(
      evhtp_connection_new_dns(base_.get(), GetDns(), host.c_str(), port));
}

evhtp_connection_t* Base::HttpsConnectionNew(const string& host,
                                             unsigned short port,
                                             SSL_CTX* ssl_ctx) {
  CHECK_NOTNULL(ssl_ctx);

  // TODO(alcutter): remove this all temporary name resolution stuff when this
  // PR is merged: https://github.com/ellzey/libevhtp/pull/163
  const string addr_str(resolver_->Resolve(host));
  VLOG(1) << "Got addr: " << addr_str << ":" << port;
  evhtp_connection_t* ret(CHECK_NOTNULL(
      evhtp_connection_ssl_new(base_.get(), addr_str.c_str(), port, ssl_ctx)));
  return ret;
}

void Base::RunClosures(evutil_socket_t, short, void* userdata) {
  Base* self(static_cast<Base*>(CHECK_NOTNULL(userdata)));

  vector<function<void()>> closures;
  {
    lock_guard<mutex> lock(self->closures_lock_);
    closures.swap(self->closures_);
  }

  for (const auto& closure : closures) {
    closure();
  }
}

Event::Event(const Base& base, evutil_socket_t sock, short events,
             const Callback& cb)
    : cb_(cb), ev_(base.EventNew(sock, events, this)) {
}

Event::~Event() {
  event_free(ev_);
}

void Event::Add(const duration<double>& timeout) const {
  timeval tv;
  timeval* tvp(NULL);

  if (timeout != duration<double>::zero()) {
    const seconds sec(duration_cast<seconds>(timeout));
    tv.tv_sec = sec.count();
    tv.tv_usec = duration_cast<microseconds>(timeout - sec).count();
    tvp = &tv;
  }

  CHECK_EQ(event_add(ev_, tvp), 0);
}

void Event::Dispatch(evutil_socket_t sock, short events, void* userdata) {
  static_cast<Event*>(userdata)->cb_(sock, events);
}

HttpServer::HttpServer(const Base& base) : http_(base.HttpNew()) {
}

HttpServer::~HttpServer() {
  evhttp_free(http_);
  for (vector<Handler*>::iterator it = handlers_.begin();
       it != handlers_.end(); ++it) {
    delete *it;
  }
}

void HttpServer::Bind(const char* address, ev_uint16_t port) {
  CHECK_EQ(evhttp_bind_socket(http_, address, port), 0);
}

bool HttpServer::AddHandler(const string& path, const HandlerCallback& cb) {
  Handler* handler(new Handler(path, cb));
  handlers_.push_back(handler);

  return evhttp_set_cb(http_, path.c_str(), &HandleRequest, handler) == 0;
}

void HttpServer::HandleRequest(evhttp_request* req, void* userdata) {
  static_cast<Handler*>(userdata)->cb(req);
}

QueryParams ParseQuery(evhttp_request* req) {
  evkeyvalq keyval;
  QueryParams retval;

  // We return an empty result in case of a parsing error.
  if (evhttp_parse_query_str(evhttp_uri_get_query(
                                 evhttp_request_get_evhttp_uri(req)),
                             &keyval) == 0) {
    for (evkeyval* i = keyval.tqh_first; i; i = i->next.tqe_next) {
      retval.insert(make_pair(i->key, i->value));
    }
  }

  return retval;
}

bool GetParam(const QueryParams& query, const string& param, string* value) {
  CHECK_NOTNULL(value);

  auto it = query.find(param);
  if (it == query.end()) {
    return false;
  }

  const string possible_value(it->second);
  ++it;

  // Flag duplicate query parameters as invalid.
  const bool retval(it == query.end() || it->first != param);
  if (retval) {
    *value = possible_value;
  }

  return retval;
}

// Returns -1 on error, and on success too if the parameter contains
// -1 (so it's advised to only use it when expecting unsigned
// parameters).
int64_t GetIntParam(const QueryParams& query, const string& param) {
  int retval(-1);
  string value;
  if (GetParam(query, param, &value)) {
    errno = 0;
    const long num(strtol(value.c_str(), /*endptr*/ NULL, 10));
    // Detect strtol() errors or overflow/underflow when casting to
    // retval's type clips the value. We do the following by doing it,
    // and checking that they're still equal afterward (this will
    // still work if we change retval's type later on).
    retval = num;
    if (errno || static_cast<long>(retval) != num) {
      VLOG(1) << "over/underflow getting \"" << param << "\": " << retval
              << ", " << num << " (" << strerror(errno) << ")";
      retval = -1;
    }
  }

  return retval;
}

bool GetBoolParam(const QueryParams& query, const string& param) {
  string value;
  if (GetParam(query, param, &value)) {
    return (value == "true");
  } else {
    return false;
  }
}

EventPumpThread::EventPumpThread(const shared_ptr<Base>& base)
    : base_(base), pump_thread_(bind(&EventPumpThread::Pump, this)) {
}

EventPumpThread::~EventPumpThread() {
  base_->LoopExit();
  pump_thread_.join();
}

void EventPumpThread::Pump() {
  base_->Dispatch();
}

}  // namespace libevent
}  // namespace cert_trans
<commit_msg>Increase max_http_post_body_size from 32K to 64K. Some certs have *lots* of SANs.<commit_after>#include "config.h"
#include "util/libevent_wrapper.h"

#include <arpa/inet.h>
#ifdef HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h> /* DNS HEADER struct */
#endif
#include <event2/keyvalq_struct.h>
#include <event2/thread.h>
#include <evhtp.h>
#include <glog/logging.h>
#include <math.h>
#include <climits>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <netdb.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* inet_ functions / structs */
#endif
#include <resolv.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <signal.h>

using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::milliseconds;
using std::chrono::seconds;
using std::chrono::system_clock;
using std::function;
using std::lock_guard;
using std::make_pair;
using std::multimap;
using std::mutex;
using std::placeholders::_1;
using std::recursive_mutex;
using std::shared_ptr;
using std::string;
using std::unique_ptr;
using std::vector;
using util::TaskHold;

namespace {

void FreeEvDns(evdns_base* dns) {
  if (dns) {
    evdns_base_free(dns, true);
  }
}

static void Handler_ExitLoop(evutil_socket_t, short, void* base) {
  event_base_loopexit((event_base*)base, NULL);
}

void SetExitLoopHandler(event_base* base, int signum) {
  struct event* signal_event;
  // TODO(pphaneuf): this should be free'd
  signal_event = evsignal_new(base, signum, Handler_ExitLoop, base);
  CHECK_NOTNULL(signal_event);
  CHECK_GE(event_add(signal_event, NULL), 0);
}

void DelayCancel(event* timer, util::Task* task) {
  event_del(timer);
  task->Return(util::Status::CANCELLED);
}

void DelayDispatch(evutil_socket_t, short, void* userdata) {
  static_cast<util::Task*>(CHECK_NOTNULL(userdata))->Return();
}

#ifdef HAVE_THREAD_LOCAL
thread_local bool on_event_thread = false;
#elif HAVE___THREAD
__thread bool on_event_thread = false;
#else
#error No suitable thread local storage available
#endif

}  // namespace

namespace cert_trans {
namespace libevent {

struct HttpServer::Handler {
  Handler(const string& _path, const HandlerCallback& _cb)
      : path(_path), cb(_cb) {
  }

  const string path;
  const HandlerCallback cb;
};

class ResolverImpl : public Base::Resolver {
 public:
  string Resolve(const string& host) override {
    struct addrinfo* info;
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    // It seems evhtp doesn't support IPv6 addresses because it uses
    // inet_addr() to parse the passed in "stringified" address.
    // Restrict to IPv4 addresses for now:
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    const int resolved(getaddrinfo(host.c_str(), AF_UNSPEC, &hints, &info));
    if (resolved != 0) {
      LOG(WARNING) << "Failed to resolve HTTPS hostname " << host << ": "
                   << gai_strerror(resolved);
      return nullptr;
    }

    struct addrinfo* res(info);
    void* addr(nullptr);
    while (res && !addr) {
      switch (res->ai_family) {
        case AF_INET:
          addr =
              &reinterpret_cast<struct sockaddr_in*>(res->ai_addr)->sin_addr;
          break;
        case AF_INET6:
          // Just in case one day evhtp uses inet_pton()
          addr =
              &reinterpret_cast<struct sockaddr_in6*>(res->ai_addr)->sin6_addr;
          break;
        default:
          res = res->ai_next;
          break;
      }
    }

    if (!addr) {
      LOG(WARNING) << "Got no usable address for " << host;
      return nullptr;
    }

    char addr_str[INET6_ADDRSTRLEN];
    inet_ntop(res->ai_family, addr, addr_str, INET6_ADDRSTRLEN);
    freeaddrinfo(info);
    return string(addr_str);
  }
};

Base::Base() : Base(unique_ptr<Resolver>(new ResolverImpl)) {
}

Base::Base(unique_ptr<Resolver> resolver)
    : base_(CHECK_NOTNULL(event_base_new()), event_base_free),
      dns_(nullptr, FreeEvDns),
      wake_closures_(event_new(base_.get(), -1, 0, &Base::RunClosures, this),
                     &event_free),
      resolver_(std::move(resolver)) {
  evthread_make_base_notifiable(base_.get());

  // So much stuff breaks if there's not a Dns client around to keep the
  // event loop doing stuff that we may as well just have one from the get go.
  GetDns();
}

Base::~Base() {
}

// static
bool Base::OnEventThread() {
  return on_event_thread;
}

// static
void Base::CheckNotOnEventThread() {
  CHECK_EQ(false, OnEventThread());
}

void Base::Add(const function<void()>& cb) {
  lock_guard<mutex> lock(closures_lock_);
  closures_.push_back(cb);
  event_active(wake_closures_.get(), 0, 0);
}

void Base::Delay(const duration<double>& delay, util::Task* task) {
  // If the delay is zero (or less?), what the heck, we're done!
  if (delay <= delay.zero()) {
    task->Return();
    return;
  }

  // Make sure nothing "bad" happens while we're still setting up our
  // callbacks.
  TaskHold hold(task);

  event* timer(CHECK_NOTNULL(evtimer_new(base_.get(), &DelayDispatch, task)));

  // Ensure that the cancellation callback is run on this libevent::Base, to
  // avoid races during cancellation.

  // Cancellation callbacks are always called before the task enters
  // the DONE state (and "timer" is freed), and "event_del" is
  // thread-safe, so it does not matter on which thread "DelayCancel"
  // is called on.
  task->WhenCancelled(bind(DelayCancel, timer, task));

  task->CleanupWhenDone(bind(event_free, timer));

  timeval tv;
  const seconds sec(duration_cast<seconds>(delay));
  tv.tv_sec = sec.count();
  tv.tv_usec = duration_cast<microseconds>(delay - sec).count();

  CHECK_EQ(evtimer_add(timer, &tv), 0);
}

void Base::Dispatch() {
  SetExitLoopHandler(base_.get(), SIGHUP);
  SetExitLoopHandler(base_.get(), SIGINT);
  SetExitLoopHandler(base_.get(), SIGTERM);

  // There should /never/ be more than 1 thread trying to call Dispatch(), so
  // we should expect to always own the lock here.
  CHECK(dispatch_lock_.try_lock());
  LOG_IF(WARNING, on_event_thread)
      << "Huh?, Are you calling Dispatch() from a libevent thread?";
  const bool old_on_event_thread(on_event_thread);
  on_event_thread = true;
  CHECK_EQ(event_base_dispatch(base_.get()), 0);
  on_event_thread = old_on_event_thread;
  dispatch_lock_.unlock();
}

void Base::DispatchOnce() {
  // Only one thread can be running a dispatch loop at a time
  lock_guard<mutex> lock(dispatch_lock_);
  LOG_IF(WARNING, on_event_thread)
      << "Huh?, Are you calling Dispatch() from a libevent thread?";
  const bool old_on_event_thread(on_event_thread);
  on_event_thread = true;
  CHECK_EQ(event_base_loop(base_.get(), EVLOOP_ONCE), 0);
  on_event_thread = old_on_event_thread;
}

void Base::LoopExit() {
  event_base_loopexit(base_.get(), nullptr);
}

event* Base::EventNew(evutil_socket_t& sock, short events,
                      Event* event) const {
  return CHECK_NOTNULL(
      event_new(base_.get(), sock, events, &Event::Dispatch, event));
}

evhttp* Base::HttpNew() const {
  const ev_ssize_t max_http_header_size = 4096;
  const ev_ssize_t max_http_post_body_size = 65536;
  evhttp* http_session = CHECK_NOTNULL(evhttp_new(base_.get()));
  evhttp_set_max_headers_size(http_session, max_http_header_size);
  evhttp_set_max_body_size(http_session, max_http_post_body_size);
  return http_session;
}

evdns_base* Base::GetDns() {
  lock_guard<mutex> lock(dns_lock_);

  if (!dns_) {
    dns_.reset(CHECK_NOTNULL(evdns_base_new(base_.get(), 1)));
  }

  return dns_.get();
}

evhtp_connection_t* Base::HttpConnectionNew(const string& host,
                                            unsigned short port) {
  return CHECK_NOTNULL(
      evhtp_connection_new_dns(base_.get(), GetDns(), host.c_str(), port));
}

evhtp_connection_t* Base::HttpsConnectionNew(const string& host,
                                             unsigned short port,
                                             SSL_CTX* ssl_ctx) {
  CHECK_NOTNULL(ssl_ctx);

  // TODO(alcutter): remove this all temporary name resolution stuff when this
  // PR is merged: https://github.com/ellzey/libevhtp/pull/163
  const string addr_str(resolver_->Resolve(host));
  VLOG(1) << "Got addr: " << addr_str << ":" << port;
  evhtp_connection_t* ret(CHECK_NOTNULL(
      evhtp_connection_ssl_new(base_.get(), addr_str.c_str(), port, ssl_ctx)));
  return ret;
}

void Base::RunClosures(evutil_socket_t, short, void* userdata) {
  Base* self(static_cast<Base*>(CHECK_NOTNULL(userdata)));

  vector<function<void()>> closures;
  {
    lock_guard<mutex> lock(self->closures_lock_);
    closures.swap(self->closures_);
  }

  for (const auto& closure : closures) {
    closure();
  }
}

Event::Event(const Base& base, evutil_socket_t sock, short events,
             const Callback& cb)
    : cb_(cb), ev_(base.EventNew(sock, events, this)) {
}

Event::~Event() {
  event_free(ev_);
}

void Event::Add(const duration<double>& timeout) const {
  timeval tv;
  timeval* tvp(NULL);

  if (timeout != duration<double>::zero()) {
    const seconds sec(duration_cast<seconds>(timeout));
    tv.tv_sec = sec.count();
    tv.tv_usec = duration_cast<microseconds>(timeout - sec).count();
    tvp = &tv;
  }

  CHECK_EQ(event_add(ev_, tvp), 0);
}

void Event::Dispatch(evutil_socket_t sock, short events, void* userdata) {
  static_cast<Event*>(userdata)->cb_(sock, events);
}

HttpServer::HttpServer(const Base& base) : http_(base.HttpNew()) {
}

HttpServer::~HttpServer() {
  evhttp_free(http_);
  for (vector<Handler*>::iterator it = handlers_.begin();
       it != handlers_.end(); ++it) {
    delete *it;
  }
}

void HttpServer::Bind(const char* address, ev_uint16_t port) {
  CHECK_EQ(evhttp_bind_socket(http_, address, port), 0);
}

bool HttpServer::AddHandler(const string& path, const HandlerCallback& cb) {
  Handler* handler(new Handler(path, cb));
  handlers_.push_back(handler);

  return evhttp_set_cb(http_, path.c_str(), &HandleRequest, handler) == 0;
}

void HttpServer::HandleRequest(evhttp_request* req, void* userdata) {
  static_cast<Handler*>(userdata)->cb(req);
}

QueryParams ParseQuery(evhttp_request* req) {
  evkeyvalq keyval;
  QueryParams retval;

  // We return an empty result in case of a parsing error.
  if (evhttp_parse_query_str(evhttp_uri_get_query(
                                 evhttp_request_get_evhttp_uri(req)),
                             &keyval) == 0) {
    for (evkeyval* i = keyval.tqh_first; i; i = i->next.tqe_next) {
      retval.insert(make_pair(i->key, i->value));
    }
  }

  return retval;
}

bool GetParam(const QueryParams& query, const string& param, string* value) {
  CHECK_NOTNULL(value);

  auto it = query.find(param);
  if (it == query.end()) {
    return false;
  }

  const string possible_value(it->second);
  ++it;

  // Flag duplicate query parameters as invalid.
  const bool retval(it == query.end() || it->first != param);
  if (retval) {
    *value = possible_value;
  }

  return retval;
}

// Returns -1 on error, and on success too if the parameter contains
// -1 (so it's advised to only use it when expecting unsigned
// parameters).
int64_t GetIntParam(const QueryParams& query, const string& param) {
  int retval(-1);
  string value;
  if (GetParam(query, param, &value)) {
    errno = 0;
    const long num(strtol(value.c_str(), /*endptr*/ NULL, 10));
    // Detect strtol() errors or overflow/underflow when casting to
    // retval's type clips the value. We do the following by doing it,
    // and checking that they're still equal afterward (this will
    // still work if we change retval's type later on).
    retval = num;
    if (errno || static_cast<long>(retval) != num) {
      VLOG(1) << "over/underflow getting \"" << param << "\": " << retval
              << ", " << num << " (" << strerror(errno) << ")";
      retval = -1;
    }
  }

  return retval;
}

bool GetBoolParam(const QueryParams& query, const string& param) {
  string value;
  if (GetParam(query, param, &value)) {
    return (value == "true");
  } else {
    return false;
  }
}

EventPumpThread::EventPumpThread(const shared_ptr<Base>& base)
    : base_(base), pump_thread_(bind(&EventPumpThread::Pump, this)) {
}

EventPumpThread::~EventPumpThread() {
  base_->LoopExit();
  pump_thread_.join();
}

void EventPumpThread::Pump() {
  base_->Dispatch();
}

}  // namespace libevent
}  // namespace cert_trans
<|endoftext|>


<commit_before>#include "async.h"
#include "chord.h"
#include "dhash.h"
#include "dbfe.h"

#include "rxx.h"
#include "async.h"

char *dbname;
chordID minID, maxID;
u_int block_size;
u_int num_blocks;

void
usage ()
{
  fatal << "USAGE: builddb <dbname> <minID> <maxID> <bytes/block> <#blocks>\n";
}

ptr<dbfe>
opendb()
{
  unlink (dbname);

  dbOptions opts;
  opts.addOption("opt_async", 1);
  opts.addOption("opt_cachesize", 1000);
  opts.addOption("opt_nodesize", 4096);

  ptr<dbfe> db = New refcounted<dbfe>();
  if (int err = db->opendb(dbname, opts)) {
    warn << "db file: " << dbname <<"\n";
    warn << "open returned: " << strerror(err) << "\n";
    exit (-1);
  }

  return db;
}

int
main (int argc, char** argv)
{
  setprogname (argv[0]);
  sfsconst_init ();
  random_init ();

  if (argc != 6
      || !str2chordID (argv[2], minID)
      || !str2chordID (argv[3], maxID)
      || !(block_size = atoi (argv[4]))
      || !(num_blocks = atoi (argv[5])))
    usage ();

  dbname = argv[1];

  warn << "PARAMS dbname '" << dbname
       << "', minID " << minID
       << ", maxID " << maxID
       << ", bytes/block " << block_size
       << ", #blocks " << num_blocks
       << "\n";

  ptr<dbfe> db = opendb ();

  char block[block_size];
  bzero (block, block_size);
  u_int n = 0;
  for (u_int i = 0; i < num_blocks; i++) {
    // start of block contains 'i', the rest is all zeroed
    ((u_int *)block)[0] = i;

    char hash[sha1::hashsize];
    sha1_hash (hash, block, block_size);
    chordID ID;
    mpz_set_rawmag_be (&ID, hash, sizeof (hash));

    if (between (minID, maxID, ID)) {
      n++;
      ref<dbrec> key = New refcounted<dbrec> (&hash[0], sha1::hashsize);
      ref<dbrec> data = New refcounted<dbrec> (&block[0], block_size);
      db->insert (key, data);
      warn << n << "\n";
    }
  }

  db->sync ();

  warn << n << "/" << num_blocks << " blocks inserted in " << dbname << ".\n";
}

<commit_msg>don't call sfsconst_init () since planet lab nodes do not have an sfs user/group<commit_after>#include "async.h"
#include "chord.h"
#include "dhash.h"
#include "dbfe.h"

#include "rxx.h"
#include "async.h"

char *dbname;
chordID minID, maxID;
u_int block_size;
u_int num_blocks;

void
usage ()
{
  fatal << "USAGE: builddb <dbname> <minID> <maxID> <bytes/block> <#blocks>\n";
}

ptr<dbfe>
opendb()
{
  unlink (dbname);

  dbOptions opts;
  opts.addOption("opt_async", 1);
  opts.addOption("opt_cachesize", 1000);
  opts.addOption("opt_nodesize", 4096);

  ptr<dbfe> db = New refcounted<dbfe>();
  if (int err = db->opendb(dbname, opts)) {
    warn << "db file: " << dbname <<"\n";
    warn << "open returned: " << strerror(err) << "\n";
    exit (-1);
  }

  return db;
}

int
main (int argc, char** argv)
{
  setprogname (argv[0]);
  random_init ();

  if (argc != 6
      || !str2chordID (argv[2], minID)
      || !str2chordID (argv[3], maxID)
      || !(block_size = atoi (argv[4]))
      || !(num_blocks = atoi (argv[5])))
    usage ();

  dbname = argv[1];

  warn << "PARAMS dbname '" << dbname
       << "', minID " << minID
       << ", maxID " << maxID
       << ", bytes/block " << block_size
       << ", #blocks " << num_blocks
       << "\n";

  ptr<dbfe> db = opendb ();

  char block[block_size];
  bzero (block, block_size);
  u_int n = 0;
  for (u_int i = 0; i < num_blocks; i++) {
    // start of block contains 'i', the rest is all zeroed
    ((u_int *)block)[0] = i;

    char hash[sha1::hashsize];
    sha1_hash (hash, block, block_size);
    chordID ID;
    mpz_set_rawmag_be (&ID, hash, sizeof (hash));

    if (between (minID, maxID, ID)) {
      n++;
      ref<dbrec> key = New refcounted<dbrec> (&hash[0], sha1::hashsize);
      ref<dbrec> data = New refcounted<dbrec> (&block[0], block_size);
      db->insert (key, data);
      warn << n << "\n";
    }
  }

  db->sync ();

  warn << n << "/" << num_blocks << " blocks inserted in " << dbname << ".\n";
}

<|endoftext|>