<commit_before>/*
  Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "swirl_user.h"

#include <fclaw_package.h>

#include <fclaw2d_forestclaw.h>
#include <fclaw2d_options.h>
#include <fclaw2d_domain.h>
#include <fclaw2d_diagnostics.h>
#include <fclaw2d_convenience.h>
#include <fclaw2d_global.h>
#include <fclaw2d_vtable.h>

#include <fc2d_clawpack46_options.h>
#include <fc2d_clawpack5_options.h>

static int s_user_options_package_id = -1;

static void *
user_register (user_options_t *user, sc_options_t * opt)
{
    /* [user] User options */
    sc_options_add_double (opt, 0, "period", &user->period, 4,
                           "Period of the flow field [4]");

    sc_options_add_int (opt, 0, "claw-version", &user->claw_version, 5,
                           "Clawpack_version (4 or 5) [5]");

    user->is_registered = 1;

    return NULL;
}

static fclaw_exit_type_t
user_postprocess(user_options_t *user)
{
    /* nothing to post-process yet ... */
    return FCLAW_NOEXIT;
}

static fclaw_exit_type_t
user_check (user_options_t *user)
{
    /* Nothing to check ? */
    return FCLAW_NOEXIT;
}

static fclaw_exit_type_t
user_destroy(user_options_t *user)
{
    /* Nothing to destroy */
    return FCLAW_NOEXIT;
}

/* ------- Generic option handling routines that call above routines ----- */
static void*
options_register (fclaw_app_t * app, void *package, sc_options_t * opt)
{
    user_options_t *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (opt != NULL);

    user = (user_options_t*) package;

    return user_register(user,opt);
}

static fclaw_exit_type_t
options_postprocess (fclaw_app_t * a, void *package, void *registered)
{
    FCLAW_ASSERT (a != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (registered == NULL);

    /* errors from the key-value options would have showed up in parsing */
    user_options_t *user = (user_options_t *) package;

    /* post-process this package */
    FCLAW_ASSERT(user->is_registered);

    /* Convert strings to arrays */
    return user_postprocess (user);
}

static fclaw_exit_type_t
options_check(fclaw_app_t *app, void *package,void *registered)
{
    user_options_t           *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT(registered == NULL);

    user = (user_options_t*) package;

    return user_check(user);
}

static void
options_destroy (fclaw_app_t * app, void *package, void *registered)
{
    user_options_t *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (registered == NULL);

    user = (user_options_t*) package;
    FCLAW_ASSERT (user->is_registered);

    user_destroy (user);

    FCLAW_FREE (user);
}

static const fclaw_app_options_vtable_t options_vtable_user =
{
    options_register,
    options_postprocess,
    options_check,
    options_destroy
};

/* ------------- User options access functions --------------------- */

static
user_options_t* user_options_register (fclaw_app_t * app,
                                       const char *configfile)
{
    user_options_t *user;
    FCLAW_ASSERT (app != NULL);

    user = FCLAW_ALLOC (user_options_t, 1);
    fclaw_app_options_register (app,"user", configfile, &options_vtable_user,
                                user);

    fclaw_app_set_attribute(app,"user",user);
    return user;
}

static
void user_options_store (fclaw2d_global_t* glob, user_options_t* user)
{
    FCLAW_ASSERT(s_user_options_package_id == -1);
    int id = fclaw_package_container_add_pkg(glob,user);
    s_user_options_package_id = id;
}

const user_options_t* swirl_get_options(fclaw2d_global_t* glob)
{
    int id = s_user_options_package_id;
    return (user_options_t*) fclaw_package_get_options(glob, id);
}
/* ------------------------- ... and here ---------------------------- */

static
fclaw2d_domain_t* create_domain(sc_MPI_Comm mpicomm, fclaw_options_t* gparms)
{
    /* Mapped, multi-block domain */
    p4est_connectivity_t     *conn = NULL;
    fclaw2d_domain_t         *domain;
    fclaw2d_map_context_t    *cont = NULL;

    /* Map unit square to disk using mapc2m_disk.f */
    gparms->manifold = 0;
    conn = p4est_connectivity_new_unitsquare();
    cont = fclaw2d_map_new_nomap();

    domain = fclaw2d_domain_new_conn_map (mpicomm, gparms->minlevel, conn, cont);
    fclaw2d_domain_list_levels(domain, FCLAW_VERBOSITY_ESSENTIAL);
    fclaw2d_domain_list_neighbors(domain, FCLAW_VERBOSITY_DEBUG);
    return domain;
}

static
void run_program(fclaw2d_global_t* glob)
{
    user_options_t           *user;

    /* ---------------------------------------------------------------
       Set domain data.
       --------------------------------------------------------------- */
    fclaw2d_domain_data_new(glob->domain);

    user = (user_options_t*) swirl_get_options(glob);

    /* Initialize virtual table for ForestClaw */
    fclaw2d_vtable_initialize();
    fclaw2d_diagnostics_vtable_initialize();

    /* Initialize virtual tables for solvers */
    if (user->claw_version == 4)
    {
        fc2d_clawpack46_vtable_initialize();
    }
    else if (user->claw_version == 5)
    {
        fc2d_clawpack5_vtable_initialize();
    }

    swirl_link_solvers(glob);

    /* ---------------------------------------------------------------
       Run
       --------------------------------------------------------------- */
    fclaw2d_initialize(glob);
    fclaw2d_run(glob);
    fclaw2d_finalize(glob);
}

int
main (int argc, char **argv)
{
    fclaw_app_t *app;
    int first_arg;
    fclaw_exit_type_t vexit;

    /* Options */
    sc_options_t                *options;
    user_options_t              *user;
    fclaw_options_t               *gparms;
    fclaw2d_clawpatch_options_t *clawpatchopt;
    fc2d_clawpack46_options_t   *claw46opt;
    fc2d_clawpack5_options_t    *claw5opt;

    fclaw2d_global_t         *glob;
    fclaw2d_domain_t         *domain;
    sc_MPI_Comm mpicomm;

    int retval;

    /* Initialize application */
    app = fclaw_app_new (&argc, &argv, NULL);

    /* Create new options packages */
    gparms =                     fclaw_options_register(app,"fclaw_options.ini");
    clawpatchopt =   fclaw2d_clawpatch_options_register(app,"fclaw_options.ini");
    claw46opt =        fc2d_clawpack46_options_register(app,"fclaw_options.ini");
    claw5opt =          fc2d_clawpack5_options_register(app,"fclaw_options.ini");
    user =                        user_options_register(app,"fclaw_options.ini");

    /* Read configuration file(s) and command line, and process options */
    options = fclaw_app_get_options (app);
    retval = fclaw_options_read_from_file(options);
    vexit =  fclaw_app_options_parse (app, &first_arg,"fclaw_options.ini.used");

    /* at this point gparms is valid */
    mpicomm = fclaw_app_get_mpi_size_rank (app, NULL, NULL);
    domain = create_domain(mpicomm, gparms);

    /* Create global structure which stores the domain, timers, etc */
    glob = fclaw2d_global_new();
    fclaw2d_global_store_domain(glob, domain);

    /* Store option packages in glob */
    fclaw2d_options_store (glob, gparms);
    fclaw2d_clawpatch_options_store (glob, clawpatchopt);
    fc2d_clawpack46_options_store (glob, claw46opt);
    fc2d_clawpack5_options_store (glob, claw5opt);
    user_options_store (glob, user);

    /* Run the program */
    if (!retval & !vexit)
    {
        run_program(glob);
    }

    fclaw2d_global_destroy(glob);
    fclaw_app_destroy (app);

    return 0;
}
<commit_msg>(swirl) more work on options<commit_after>/*
  Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "swirl_user.h"

#include <fclaw_package.h>

#include <fclaw2d_forestclaw.h>
#include <fclaw2d_options.h>
#include <fclaw2d_domain.h>
#include <fclaw2d_diagnostics.h>
#include <fclaw2d_convenience.h>
#include <fclaw2d_global.h>
#include <fclaw2d_vtable.h>

#include <fclaw2d_clawpatch_options.h>
#include <fclaw2d_clawpatch.h>

#include <fc2d_clawpack46_options.h>
#include <fc2d_clawpack5_options.h>

#include <fc2d_clawpack46.h>
#include <fc2d_clawpack5.h>

static int s_user_options_package_id = -1;

static void *
swirl_register (user_options_t *user, sc_options_t * opt)
{
    /* [user] User options */
    sc_options_add_double (opt, 0, "period", &user->period, 4,
                           "Period of the flow field [4]");

    sc_options_add_int (opt, 0, "claw-version", &user->claw_version, 5,
                           "Clawpack_version (4 or 5) [5]");

    user->is_registered = 1;

    return NULL;
}

static fclaw_exit_type_t
swirl_postprocess(user_options_t *user)
{
    /* nothing to post-process yet ... */
    return FCLAW_NOEXIT;
}

static fclaw_exit_type_t
swirl_check (user_options_t *user)
{
    /* Nothing to check ? */
    return FCLAW_NOEXIT;
}

static fclaw_exit_type_t
swirl_destroy(user_options_t *user)
{
    /* Nothing to destroy */
    return FCLAW_NOEXIT;
}

/* ------- Generic option handling routines that call above routines ----- */
static void*
options_register (fclaw_app_t * app, void *package, sc_options_t * opt)
{
    user_options_t *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (opt != NULL);

    user = (user_options_t*) package;

    return swirl_register(user,opt);
}

static fclaw_exit_type_t
options_postprocess (fclaw_app_t * a, void *package, void *registered)
{
    FCLAW_ASSERT (a != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (registered == NULL);

    /* errors from the key-value options would have showed up in parsing */
    user_options_t *user = (user_options_t *) package;

    /* post-process this package */
    FCLAW_ASSERT(user->is_registered);

    /* Convert strings to arrays */
    return swirl_postprocess (user);
}

static fclaw_exit_type_t
options_check(fclaw_app_t *app, void *package,void *registered)
{
    user_options_t           *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT(registered == NULL);

    user = (user_options_t*) package;

    return swirl_check(user);
}

static void
options_destroy (fclaw_app_t * app, void *package, void *registered)
{
    user_options_t *user;

    FCLAW_ASSERT (app != NULL);
    FCLAW_ASSERT (package != NULL);
    FCLAW_ASSERT (registered == NULL);

    user = (user_options_t*) package;
    FCLAW_ASSERT (user->is_registered);

    swirl_destroy (user);

    FCLAW_FREE (user);
}

static const fclaw_app_options_vtable_t options_vtable_user =
{
    options_register,
    options_postprocess,
    options_check,
    options_destroy
};

/* ------------- User options access functions --------------------- */

static
user_options_t* swirl_options_register (fclaw_app_t * app,
                                       const char *configfile)
{
    user_options_t *user;
    FCLAW_ASSERT (app != NULL);

    user = FCLAW_ALLOC (user_options_t, 1);
    fclaw_app_options_register (app,"user", configfile, &options_vtable_user,
                                user);

    fclaw_app_set_attribute(app,"user",user);
    return user;
}

static
void user_options_store (fclaw2d_global_t* glob, user_options_t* user)
{
    FCLAW_ASSERT(s_user_options_package_id == -1);
    int id = fclaw_package_container_add_pkg(glob,user);
    s_user_options_package_id = id;
}

const user_options_t* swirl_get_options(fclaw2d_global_t* glob)
{
    int id = s_user_options_package_id;
    return (user_options_t*) fclaw_package_get_options(glob, id);
}
/* ------------------------- ... and here ---------------------------- */

static
fclaw2d_domain_t* create_domain(sc_MPI_Comm mpicomm, fclaw_options_t* gparms)
{
    /* Mapped, multi-block domain */
    p4est_connectivity_t     *conn = NULL;
    fclaw2d_domain_t         *domain;
    fclaw2d_map_context_t    *cont = NULL;

    /* Map unit square to disk using mapc2m_disk.f */
    gparms->manifold = 0;
    conn = p4est_connectivity_new_unitsquare();
    cont = fclaw2d_map_new_nomap();

    domain = fclaw2d_domain_new_conn_map (mpicomm, gparms->minlevel, conn, cont);
    fclaw2d_domain_list_levels(domain, FCLAW_VERBOSITY_ESSENTIAL);
    fclaw2d_domain_list_neighbors(domain, FCLAW_VERBOSITY_DEBUG);
    return domain;
}

static
void run_program(fclaw2d_global_t* glob)
{
    user_options_t           *user;

    /* ---------------------------------------------------------------
       Set domain data.
       --------------------------------------------------------------- */
    fclaw2d_domain_data_new(glob->domain);

    user = (user_options_t*) swirl_get_options(glob);

    /* Initialize virtual table for ForestClaw */
    fclaw2d_vtable_initialize();
    fclaw2d_diagnostics_vtable_initialize();

    /* Initialize virtual tables for solvers */
    if (user->claw_version == 4)
    {
        fc2d_clawpack46_vtable_initialize();
    }
    else if (user->claw_version == 5)
    {
        fc2d_clawpack5_vtable_initialize();
    }

    swirl_link_solvers(glob);

    /* ---------------------------------------------------------------
       Run
       --------------------------------------------------------------- */
    fclaw2d_initialize(glob);
    fclaw2d_run(glob);
    fclaw2d_finalize(glob);
}

int
main (int argc, char **argv)
{
    fclaw_app_t *app;
    int first_arg;
    fclaw_exit_type_t vexit;

    /* Options */
    sc_options_t                *options;
    user_options_t              *user;
    fclaw_options_t             *gparms;
    fclaw2d_clawpatch_options_t *clawpatchopt;
    fc2d_clawpack46_options_t   *claw46opt;
    fc2d_clawpack5_options_t    *claw5opt;

    fclaw2d_global_t         *glob;
    fclaw2d_domain_t         *domain;
    sc_MPI_Comm mpicomm;

    int retval;

    /* Initialize application */
    app = fclaw_app_new (&argc, &argv, NULL);

    /* Create new options packages */
    gparms =                     fclaw_options_register(app,"fclaw_options.ini");
    clawpatchopt =   fclaw2d_clawpatch_options_register(app,"fclaw_options.ini");
    claw46opt =        fc2d_clawpack46_options_register(app,"fclaw_options.ini");
    claw5opt =          fc2d_clawpack5_options_register(app,"fclaw_options.ini");
    user =                        swirl_options_register(app,"fclaw_options.ini");

    /* Read configuration file(s) and command line, and process options */
    options = fclaw_app_get_options (app);
    retval = fclaw_options_read_from_file(options);
    vexit =  fclaw_app_options_parse (app, &first_arg,"fclaw_options.ini.used");

    /* at this point gparms is valid */
    mpicomm = fclaw_app_get_mpi_size_rank (app, NULL, NULL);
    domain = create_domain(mpicomm, gparms);

    /* Create global structure which stores the domain, timers, etc */
    glob = fclaw2d_global_new();
    fclaw2d_global_store_domain(glob, domain);

    /* Store option packages in glob */
    fclaw2d_options_store (glob, gparms);
    fclaw2d_clawpatch_options_store (glob, clawpatchopt);
    fc2d_clawpack46_options_store (glob, claw46opt);
    fc2d_clawpack5_options_store (glob, claw5opt);
    user_options_store (glob, user);

    /* Run the program */
    if (!retval & !vexit)
    {
        run_program(glob);
    }

    fclaw2d_global_destroy(glob);
    fclaw_app_destroy (app);

    return 0;
}
<|endoftext|>


<commit_before>// Ouzel by Elviss Strazdins

#ifndef OUZEL_FORMATS_INI_HPP
#define OUZEL_FORMATS_INI_HPP

#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <map>
#include <stdexcept>
#include <string>
#include <string_view>

namespace ouzel::ini
{
    class ParseError final: public std::logic_error
    {
    public:
        using std::logic_error::logic_error;
    };

    class RangeError final: public std::range_error
    {
    public:
        using std::range_error::range_error;
    };

    using Values = std::map<std::string, std::string, std::less<>>;

    class Section final
    {
    public:
        Section() = default;

        explicit Section(const std::string& initName):
            name{initName}
        {
        }

        auto begin() noexcept
        {
            return values.begin();
        }

        auto end() noexcept
        {
            return values.end();
        }

        auto begin() const noexcept
        {
            return values.begin();
        }

        auto end() const noexcept
        {
            return values.end();
        }

        const std::string& getName() const noexcept { return name; }
        void setName(const std::string& newName) { name = newName; }

        const Values& getValues() const noexcept { return values; }

        bool hasValue(const std::string_view key) const
        {
            return values.find(key) != values.end();
        }

        std::string& operator[](const std::string_view key)
        {
            if (const auto valueIterator = values.find(key); valueIterator != values.end())
                return valueIterator->second;
            else
            {
                const auto& [newIterator, success] = values.insert(std::make_pair(key, std::string{}));
                (void)success;
                return newIterator->second;
            }
        }

        const std::string& operator[](const std::string_view key) const
        {
            if (const auto valueIterator = values.find(key); valueIterator != values.end())
                return valueIterator->second;
            else
                throw RangeError{"Value does not exist"};
        }

        const std::string& getValue(const std::string_view key, const std::string& defaultValue = {}) const
        {
            if (const auto valueIterator = values.find(key); valueIterator != values.end())
                return valueIterator->second;

            return defaultValue;
        }

        void deleteValue(const std::string_view key)
        {
            if (const auto valueIterator = values.find(key); valueIterator != values.end())
                values.erase(valueIterator);
        }

        std::size_t getSize() const noexcept
        {
            return values.size();
        }

    private:
        std::string name;
        Values values;
    };

    class Data final
    {
    public:
        using Sections = std::map<std::string, Section, std::less<>>;

        Data() = default;

        const Sections& getSections() const noexcept { return sections; }

        auto begin() noexcept
        {
            return sections.begin();
        }

        auto end() noexcept
        {
            return sections.end();
        }

        auto begin() const noexcept
        {
            return sections.begin();
        }

        auto end() const noexcept
        {
            return sections.end();
        }

        bool hasSection(const std::string_view name) const
        {
            return sections.find(name) != sections.end();
        }

        Section& operator[](const std::string_view name)
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                return sectionIterator->second;
            else
            {
                const auto& [newIterator, success] = sections.insert(std::make_pair(name, Section{}));
                (void)success;
                return newIterator->second;
            }
        }

        const Section& operator[](const std::string_view name) const
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                return sectionIterator->second;
            else
                throw RangeError{"Section does not exist"};
        }

        void eraseSection(const std::string_view name)
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                sections.erase(sectionIterator);
        }

        std::size_t getSize() const noexcept
        {
            return sections.size();
        }

    private:
        Sections sections;
    };

    inline namespace detail
    {
        constexpr std::array<std::uint8_t, 3> utf8ByteOrderMark = {0xEF, 0xBB, 0xBF};
    }

    template <class Iterator>
    Data parse(Iterator begin, Iterator end)
    {
        class Parser final
        {
        public:
            static Data parse(Iterator begin, Iterator end)
            {
                Data result;

                std::string section;

                for (auto iterator = hasByteOrderMark(begin, end) ? begin + 3 : begin; iterator != end;)
                {
                    if (isWhitespace(static_cast<char>(*iterator)) ||
                        static_cast<char>(*iterator) == '\n' ||
                        static_cast<char>(*iterator) == '\r') // line starts with a whitespace
                        ++iterator; // skip the white space
                    else if (static_cast<char>(*iterator) == '[') // section
                    {
                        ++iterator; // skip the left bracket

                        bool parsedSection = false;

                        for (;;)
                        {
                            if (iterator == end ||
                                static_cast<char>(*iterator) == '\n' ||
                                static_cast<char>(*iterator) == '\r')
                            {
                                if (!parsedSection)
                                    throw ParseError{"Unexpected end of section"};

                                ++iterator; // skip the newline
                                break;
                            }
                            else if (static_cast<char>(*iterator) == ';')
                            {
                                ++iterator; // skip the semicolon

                                if (!parsedSection)
                                    throw ParseError{"Unexpected comment"};

                                while (iterator != end)
                                {
                                    if (static_cast<char>(*iterator) == '\n' ||
                                        static_cast<char>(*iterator) == '\r')
                                    {
                                        ++iterator; // skip the newline
                                        break;
                                    }

                                    ++iterator;
                                }
                                break;
                            }
                            else if (static_cast<char>(*iterator) == ']')
                                parsedSection = true;
                            else if (static_cast<char>(*iterator) != ' ' &&
                                     static_cast<char>(*iterator) != '\t')
                            {
                                if (parsedSection)
                                    throw ParseError{"Unexpected character after section"};
                            }

                            if (!parsedSection)
                                section.push_back(static_cast<char>(*iterator));

                            ++iterator;
                        }

                        trim(section);

                        if (section.empty())
                            throw ParseError{"Invalid section name"};

                        result[section] = Section{};
                    }
                    else if (static_cast<char>(*iterator) == ';') // comment
                    {
                        while (++iterator != end)
                        {
                            if (static_cast<char>(*iterator) == '\r' ||
                                static_cast<char>(*iterator) == '\n')
                            {
                                ++iterator; // skip the newline
                                break;
                            }
                        }
                    }
                    else // key, value pair
                    {
                        std::string key;
                        std::string value;
                        bool parsedKey = false;

                        while (iterator != end)
                        {
                            if (static_cast<char>(*iterator) == '\r' ||
                                static_cast<char>(*iterator) == '\n')
                            {
                                ++iterator; // skip the newline
                                break;
                            }
                            else if (static_cast<char>(*iterator) == '=')
                            {
                                if (!parsedKey)
                                    parsedKey = true;
                                else
                                    throw ParseError{"Unexpected character"};
                            }
                            else if (static_cast<char>(*iterator) == ';')
                            {
                                ++iterator; // skip the semicolon

                                while (iterator != end)
                                {
                                    if (static_cast<char>(*iterator) == '\r' ||
                                        static_cast<char>(*iterator) == '\n')
                                    {
                                        ++iterator; // skip the newline
                                        break;
                                    }

                                    ++iterator;
                                }
                                break;
                            }
                            else
                            {
                                if (!parsedKey)
                                    key.push_back(static_cast<char>(*iterator));
                                else
                                    value.push_back(static_cast<char>(*iterator));
                            }

                            ++iterator;
                        }

                        if (key.empty())
                            throw ParseError{"Invalid key name"};

                        trim(key);
                        trim(value);

                        result[section][key] = value;
                    }
                }

                return result;
            }

        private:
            static bool hasByteOrderMark(Iterator begin, Iterator end) noexcept
            {
                for (const auto b : utf8ByteOrderMark)
                    if (begin == end || static_cast<std::uint8_t>(*begin) != b)
                        return false;
                    else
                        ++begin;
                return true;
            }

            static constexpr bool isWhitespace(const char c) noexcept
            {
                return c == ' ' || c == '\t';
            }

            static std::string& leftTrim(std::string& s)
            {
                s.erase(s.begin(), std::find_if(s.begin(), s.end(),
                                                [](char c) noexcept {return !isWhitespace(c);}));
                return s;
            }

            static std::string& rightTrim(std::string& s)
            {
                s.erase(std::find_if(s.rbegin(), s.rend(),
                                     [](char c) noexcept {return !isWhitespace(c);}).base(), s.end());
                return s;
            }

            static std::string& trim(std::string& s)
            {
                return leftTrim(rightTrim(s));
            }
        };

        return Parser::parse(begin, end);
    }

    inline Data parse(const char* data)
    {
        auto end = data;
        while (*end) ++end;
        return parse(data, end);
    }

    template <class T>
    Data parse(const T& data)
    {
        return parse(std::begin(data), std::end(data));
    }

    inline std::string encode(const Data& data, bool byteOrderMark = false)
    {
        std::string result;

        if (byteOrderMark) result.assign(utf8ByteOrderMark.begin(),
                                         utf8ByteOrderMark.end());

        for (const auto& [name, section] : data)
        {
            if (!name.empty())
            {
                result.push_back('[');
                result.insert(result.end(), name.begin(), name.end());
                result.push_back(']');
                result.push_back('\n');
            }

            for (const auto& [key, value] : section)
            {
                result.insert(result.end(), key.begin(), key.end());
                result.push_back('=');
                result.insert(result.end(), value.begin(), value.end());
                result.push_back('\n');
            }
        }

        return result;
    }
}

#endif // OUZEL_FORMATS_INI_HPP
<commit_msg>Rename valueIterator to iterator<commit_after>// Ouzel by Elviss Strazdins

#ifndef OUZEL_FORMATS_INI_HPP
#define OUZEL_FORMATS_INI_HPP

#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <map>
#include <stdexcept>
#include <string>
#include <string_view>

namespace ouzel::ini
{
    class ParseError final: public std::logic_error
    {
    public:
        using std::logic_error::logic_error;
    };

    class RangeError final: public std::range_error
    {
    public:
        using std::range_error::range_error;
    };

    using Values = std::map<std::string, std::string, std::less<>>;

    class Section final
    {
    public:
        Section() = default;

        explicit Section(const std::string& initName):
            name{initName}
        {
        }

        auto begin() noexcept
        {
            return values.begin();
        }

        auto end() noexcept
        {
            return values.end();
        }

        auto begin() const noexcept
        {
            return values.begin();
        }

        auto end() const noexcept
        {
            return values.end();
        }

        const std::string& getName() const noexcept { return name; }
        void setName(const std::string& newName) { name = newName; }

        const Values& getValues() const noexcept { return values; }

        bool hasValue(const std::string_view key) const
        {
            return values.find(key) != values.end();
        }

        std::string& operator[](const std::string_view key)
        {
            if (const auto iterator = values.find(key); iterator != values.end())
                return iterator->second;
            else
            {
                const auto& [newIterator, success] = values.insert(std::make_pair(key, std::string{}));
                (void)success;
                return newIterator->second;
            }
        }

        const std::string& operator[](const std::string_view key) const
        {
            if (const auto iterator = values.find(key); iterator != values.end())
                return iterator->second;
            else
                throw RangeError{"Value does not exist"};
        }

        const std::string& getValue(const std::string_view key, const std::string& defaultValue = {}) const
        {
            if (const auto iterator = values.find(key); iterator != values.end())
                return iterator->second;

            return defaultValue;
        }

        void deleteValue(const std::string_view key)
        {
            if (const auto iterator = values.find(key); iterator != values.end())
                values.erase(iterator);
        }

        std::size_t getSize() const noexcept
        {
            return values.size();
        }

    private:
        std::string name;
        Values values;
    };

    class Data final
    {
    public:
        using Sections = std::map<std::string, Section, std::less<>>;

        Data() = default;

        const Sections& getSections() const noexcept { return sections; }

        auto begin() noexcept
        {
            return sections.begin();
        }

        auto end() noexcept
        {
            return sections.end();
        }

        auto begin() const noexcept
        {
            return sections.begin();
        }

        auto end() const noexcept
        {
            return sections.end();
        }

        bool hasSection(const std::string_view name) const
        {
            return sections.find(name) != sections.end();
        }

        Section& operator[](const std::string_view name)
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                return sectionIterator->second;
            else
            {
                const auto& [newIterator, success] = sections.insert(std::make_pair(name, Section{}));
                (void)success;
                return newIterator->second;
            }
        }

        const Section& operator[](const std::string_view name) const
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                return sectionIterator->second;
            else
                throw RangeError{"Section does not exist"};
        }

        void eraseSection(const std::string_view name)
        {
            if (const auto sectionIterator = sections.find(name); sectionIterator != sections.end())
                sections.erase(sectionIterator);
        }

        std::size_t getSize() const noexcept
        {
            return sections.size();
        }

    private:
        Sections sections;
    };

    inline namespace detail
    {
        constexpr std::array<std::uint8_t, 3> utf8ByteOrderMark = {0xEF, 0xBB, 0xBF};
    }

    template <class Iterator>
    Data parse(Iterator begin, Iterator end)
    {
        class Parser final
        {
        public:
            static Data parse(Iterator begin, Iterator end)
            {
                Data result;

                std::string section;

                for (auto iterator = hasByteOrderMark(begin, end) ? begin + 3 : begin; iterator != end;)
                {
                    if (isWhitespace(static_cast<char>(*iterator)) ||
                        static_cast<char>(*iterator) == '\n' ||
                        static_cast<char>(*iterator) == '\r') // line starts with a whitespace
                        ++iterator; // skip the white space
                    else if (static_cast<char>(*iterator) == '[') // section
                    {
                        ++iterator; // skip the left bracket

                        bool parsedSection = false;

                        for (;;)
                        {
                            if (iterator == end ||
                                static_cast<char>(*iterator) == '\n' ||
                                static_cast<char>(*iterator) == '\r')
                            {
                                if (!parsedSection)
                                    throw ParseError{"Unexpected end of section"};

                                ++iterator; // skip the newline
                                break;
                            }
                            else if (static_cast<char>(*iterator) == ';')
                            {
                                ++iterator; // skip the semicolon

                                if (!parsedSection)
                                    throw ParseError{"Unexpected comment"};

                                while (iterator != end)
                                {
                                    if (static_cast<char>(*iterator) == '\n' ||
                                        static_cast<char>(*iterator) == '\r')
                                    {
                                        ++iterator; // skip the newline
                                        break;
                                    }

                                    ++iterator;
                                }
                                break;
                            }
                            else if (static_cast<char>(*iterator) == ']')
                                parsedSection = true;
                            else if (static_cast<char>(*iterator) != ' ' &&
                                     static_cast<char>(*iterator) != '\t')
                            {
                                if (parsedSection)
                                    throw ParseError{"Unexpected character after section"};
                            }

                            if (!parsedSection)
                                section.push_back(static_cast<char>(*iterator));

                            ++iterator;
                        }

                        trim(section);

                        if (section.empty())
                            throw ParseError{"Invalid section name"};

                        result[section] = Section{};
                    }
                    else if (static_cast<char>(*iterator) == ';') // comment
                    {
                        while (++iterator != end)
                        {
                            if (static_cast<char>(*iterator) == '\r' ||
                                static_cast<char>(*iterator) == '\n')
                            {
                                ++iterator; // skip the newline
                                break;
                            }
                        }
                    }
                    else // key, value pair
                    {
                        std::string key;
                        std::string value;
                        bool parsedKey = false;

                        while (iterator != end)
                        {
                            if (static_cast<char>(*iterator) == '\r' ||
                                static_cast<char>(*iterator) == '\n')
                            {
                                ++iterator; // skip the newline
                                break;
                            }
                            else if (static_cast<char>(*iterator) == '=')
                            {
                                if (!parsedKey)
                                    parsedKey = true;
                                else
                                    throw ParseError{"Unexpected character"};
                            }
                            else if (static_cast<char>(*iterator) == ';')
                            {
                                ++iterator; // skip the semicolon

                                while (iterator != end)
                                {
                                    if (static_cast<char>(*iterator) == '\r' ||
                                        static_cast<char>(*iterator) == '\n')
                                    {
                                        ++iterator; // skip the newline
                                        break;
                                    }

                                    ++iterator;
                                }
                                break;
                            }
                            else
                            {
                                if (!parsedKey)
                                    key.push_back(static_cast<char>(*iterator));
                                else
                                    value.push_back(static_cast<char>(*iterator));
                            }

                            ++iterator;
                        }

                        if (key.empty())
                            throw ParseError{"Invalid key name"};

                        trim(key);
                        trim(value);

                        result[section][key] = value;
                    }
                }

                return result;
            }

        private:
            static bool hasByteOrderMark(Iterator begin, Iterator end) noexcept
            {
                for (const auto b : utf8ByteOrderMark)
                    if (begin == end || static_cast<std::uint8_t>(*begin) != b)
                        return false;
                    else
                        ++begin;
                return true;
            }

            static constexpr bool isWhitespace(const char c) noexcept
            {
                return c == ' ' || c == '\t';
            }

            static std::string& leftTrim(std::string& s)
            {
                s.erase(s.begin(), std::find_if(s.begin(), s.end(),
                                                [](char c) noexcept {return !isWhitespace(c);}));
                return s;
            }

            static std::string& rightTrim(std::string& s)
            {
                s.erase(std::find_if(s.rbegin(), s.rend(),
                                     [](char c) noexcept {return !isWhitespace(c);}).base(), s.end());
                return s;
            }

            static std::string& trim(std::string& s)
            {
                return leftTrim(rightTrim(s));
            }
        };

        return Parser::parse(begin, end);
    }

    inline Data parse(const char* data)
    {
        auto end = data;
        while (*end) ++end;
        return parse(data, end);
    }

    template <class T>
    Data parse(const T& data)
    {
        return parse(std::begin(data), std::end(data));
    }

    inline std::string encode(const Data& data, bool byteOrderMark = false)
    {
        std::string result;

        if (byteOrderMark) result.assign(utf8ByteOrderMark.begin(),
                                         utf8ByteOrderMark.end());

        for (const auto& [name, section] : data)
        {
            if (!name.empty())
            {
                result.push_back('[');
                result.insert(result.end(), name.begin(), name.end());
                result.push_back(']');
                result.push_back('\n');
            }

            for (const auto& [key, value] : section)
            {
                result.insert(result.end(), key.begin(), key.end());
                result.push_back('=');
                result.insert(result.end(), value.begin(), value.end());
                result.push_back('\n');
            }
        }

        return result;
    }
}

#endif // OUZEL_FORMATS_INI_HPP
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (C) 2010 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "gameproject.h"
#include "gameprojectprivate.h"

#include "scene.h"
#include "game.h"

#include "core/gdlhandler.h"
#include "core/scriptengine.h"
#include "core/debughelper.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtCore/QMetaClassInfo>
#include <QtGui/QImageWriter>

REGISTER_OBJECTTYPE( GluonEngine, GameProject )

using namespace GluonEngine;

GameProject::GameProject( QObject* parent )
    : GluonObject( parent )
    , d( new GameProjectPrivate )
{
    setGameProject( this );
}

GameProject::GameProject( const GameProject& other, QObject* parent )
    : GluonObject( parent )
    , d( other.d )
{
}

GameProject::~GameProject()
{
}

void
GameProject::addChild( GluonObject* child )
{
    GluonCore::GluonObject::addChild( child );

    connect( child, SIGNAL( showDebug( const QString& ) ), Game::instance(), SIGNAL( showDebug( const QString& ) ) );
}

bool
GameProject::removeChild( GluonObject* child )
{
    disconnect( child, SIGNAL( showDebug( const QString& ) ), Game::instance(), SIGNAL( showDebug(const QString& ) ) );

    return GluonCore::GluonObject::removeChild( child );
}

bool
GameProject::saveToFile() const
{
    // Run through everything first and save each of the saveable assets
    GameProjectPrivate::saveChildren( this );

    // Eventually, save self
    QFile projectFile( filename().toLocalFile() );
    if( !projectFile.open( QIODevice::WriteOnly ) )
        return false;

    QList<const GluonObject*> thisProject;
    thisProject.append( this );

    QTextStream projectWriter( &projectFile );
    projectWriter << GluonCore::GDLHandler::instance()->serializeGDL( thisProject );
    projectFile.close();

    QString projectDir = filename().toLocalFile().section( '/', 0, -2 );
    // Recreate the various icon files if we have an icon file available
    QImage icon(128, 128, QImage::Format_ARGB32);
    if( d->icon )
        icon = d->icon->texture()->image().scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    QString iconFile(projectDir);
    iconFile.append('/');
    iconFile.append( GluonEngine::projectIcon );
    icon.save( iconFile );
    if( QImageWriter::supportedImageFormats().contains("ico") )
    {
        iconFile = projectDir;
        iconFile.append('/');
        iconFile.append( GluonEngine::projectWinIcon );
        QImageWriter iconWriter(iconFile);
        iconWriter.setFormat("ico");
        iconWriter.write( icon );
    }

    // Build the folder information files for Windows and for XDG compliant file browsers
    QFile directoryFile( projectDir + "/.directory" );
    if( directoryFile.open( QFile::WriteOnly | QFile::Truncate ) )
    {
        QTextStream out(&directoryFile, QIODevice::WriteOnly | QIODevice::Text);
        out << QString("[Desktop Entry]\nIcon=game.png\nType=Directory\n");
        directoryFile.close();
    }
    QFile folderFile( projectDir + "/desktop.ini" );
    if( folderFile.open( QFile::WriteOnly | QFile::Truncate ) )
    {
        QTextStream out(&folderFile);
        out << QString("[.ShellClassInfo]\r\nConfirmFileOp=0\r\nIconFile=game.ico\r\nIconIndex=0\r\nInfoTip=A Gluon Game\r\n");
        folderFile.close();
    }

    // Recreate the screenshot file if we have one such
    if( d->screenshot )
    {
        QString screenshotFile = projectDir;
        screenshotFile.append('/');
        screenshotFile.append( GluonEngine::projectScreenshot );
        d->screenshot->texture()->image().scaled( 800, 600, Qt::KeepAspectRatio ).save( screenshotFile );
    }

    return true;
}

bool
GameProject::loadFromFile()
{
    DEBUG_FUNC_NAME

    // change directory to the project path..
    DEBUG_TEXT( QString( "Changing working directory to %1" ).arg( QFileInfo( filename().toLocalFile() ).canonicalPath() ) );
    QDir::setCurrent( QFileInfo( filename().toLocalFile() ).canonicalPath() );
    setFilename( filename().toLocalFile() );

    DEBUG_TEXT( QString( "Loading project from %1" ).arg( QFileInfo( filename().toLocalFile() ).fileName() ) );
    QFile projectFile( QFileInfo( filename().toLocalFile() ).fileName() );
    if( !projectFile.open( QIODevice::ReadOnly ) )
        return false;

    QTextStream projectReader( &projectFile );
    QString fileContents = projectReader.readAll();
    projectFile.close();

    if( fileContents.isEmpty() )
        return false;

    // Flush the script engine's module list. Otherwise we'll end up with state bits...
    // We do this here, since the GDL parser is likely to construct various objects which require
    // the scripting engine to be present. So, we clear it now, to be sure.
    GluonCore::ScriptEngine::instance()->resetEngine();

    QList<GluonObject*> objectList = GluonCore::GDLHandler::instance()->parseGDL( filename().toLocalFile(), parent() );
    if( objectList.count() > 0 )
    {
        if( objectList[0]->metaObject() )
        {
            // If the first object in the list is a GluonProject, then let's
            // adapt ourselves to represent that object...
            if( objectList[0]->metaObject()->className() == metaObject()->className() )
            {
                DEBUG_TEXT( "Project successfully parsed - applying to local instance" );
                GameProject* loadedProject = qobject_cast<GameProject*>( objectList[0] );

                // First things first - clean ourselves out, all the children
                // and the media info list should be gone-ified
                qDeleteAll( children() );

                // Reassign all the children of the newly loaded project to
                // ourselves...
                foreach( QObject * child, loadedProject->children() )
                {
                    GluonObject* theChild = qobject_cast<GluonObject*>( child );
                    theChild->setParent( this );
                    theChild->setGameProject( this );
                }

                // Set all the interesting values...
                setName( loadedProject->name() );

                // Copy across all the properties
                const QMetaObject* metaobject = loadedProject->metaObject();
                int count = metaobject->propertyCount();
                for( int i = 0; i < count; ++i )
                {
                    QMetaProperty metaproperty = metaobject->property( i );
                    const QString theName( metaproperty.name() );
                    if( theName == "objectName" || theName == "name" )
                        continue;
                    setProperty( metaproperty.name(), loadedProject->property( metaproperty.name() ) );
                }

                // Then get all the dynamic ones (in case any such exist)
                QList<QByteArray> propertyNames = loadedProject->dynamicPropertyNames();
                foreach( const QByteArray & propName, propertyNames )
                {
                    setProperty( propName, loadedProject->property( propName ) );
                }

                // Sanitize me!
                sanitize();

                // Finally, get rid of the left-overs
                qDeleteAll( objectList );

                DEBUG_TEXT( "Project loading successful!" );
            }
            // Otherwise it is not a GluonProject, and should fail!
            else
            {
                DEBUG_TEXT( QString( "First object loaded is not a Gluon::GameProject." ) );
                DEBUG_TEXT( QString( "Type of loaded object:" ).arg( objectList[0]->metaObject()->className() ) );
                DEBUG_TEXT( QString( "Name of loaded object:" ).arg( objectList[0]->name() ) );
                return false;
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

bool
GameProject::loadFromFile( QUrl fileUrl )
{
    setFilename( fileUrl );
    return loadFromFile();
}

bool
GameProject::loadFromFile( QString fileName )
{
    setFilename( fileName );
    return loadFromFile();
}

/******************************************************************************
 * Property Getter-setters
 *****************************************************************************/

QString
GameProject::description() const
{
    return d->description;
}

void
GameProject::setDescription( QString newDescription )
{
    d->description = newDescription;
}

QUrl
GameProject::homepage() const
{
    return d->homepage;
}
void
GameProject::setHomepage( QUrl newHomepage )
{
    d->homepage = newHomepage;
}

QList<QUrl>
GameProject::mediaInfo() const
{
    return d->mediaInfo;
}
void
GameProject::setMediaInfo( QList<QUrl> newMediaInfo )
{
    d->mediaInfo = newMediaInfo;
}

QUrl
GameProject::filename() const
{
    return d->filename;
}

void
GameProject::setFilename( QUrl fileUrl )
{
    d->filename = fileUrl;
}

void
GameProject::setFilename( QString fileName )
{
    d->filename = QUrl::fromLocalFile(fileName);
}

Scene *
GameProject::entryPoint() const
{
    return d->entryPoint;
}

void
GameProject::setEntryPoint( Scene* newEntryPoint )
{
    d->entryPoint = newEntryPoint;
}

GluonEngine::TextureAsset* GameProject::icon() const
{
    return d->icon;
}

void GameProject::setIcon(GluonEngine::TextureAsset* newIcon)
{
    d->icon = newIcon;
}

GluonEngine::TextureAsset* GameProject::screenshot() const
{
    return d->screenshot;
}

void GameProject::setScreenshot(GluonEngine::TextureAsset* newScreenshot)
{
    d->screenshot = newScreenshot;
}

#include "gameproject.moc"
<commit_msg>Fix also the folderFile related "\r\n", "\n" issues in the gameproject<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (C) 2010 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "gameproject.h"
#include "gameprojectprivate.h"

#include "scene.h"
#include "game.h"

#include "core/gdlhandler.h"
#include "core/scriptengine.h"
#include "core/debughelper.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtCore/QMetaClassInfo>
#include <QtGui/QImageWriter>

REGISTER_OBJECTTYPE( GluonEngine, GameProject )

using namespace GluonEngine;

GameProject::GameProject( QObject* parent )
    : GluonObject( parent )
    , d( new GameProjectPrivate )
{
    setGameProject( this );
}

GameProject::GameProject( const GameProject& other, QObject* parent )
    : GluonObject( parent )
    , d( other.d )
{
}

GameProject::~GameProject()
{
}

void
GameProject::addChild( GluonObject* child )
{
    GluonCore::GluonObject::addChild( child );

    connect( child, SIGNAL( showDebug( const QString& ) ), Game::instance(), SIGNAL( showDebug( const QString& ) ) );
}

bool
GameProject::removeChild( GluonObject* child )
{
    disconnect( child, SIGNAL( showDebug( const QString& ) ), Game::instance(), SIGNAL( showDebug(const QString& ) ) );

    return GluonCore::GluonObject::removeChild( child );
}

bool
GameProject::saveToFile() const
{
    // Run through everything first and save each of the saveable assets
    GameProjectPrivate::saveChildren( this );

    // Eventually, save self
    QFile projectFile( filename().toLocalFile() );
    if( !projectFile.open( QIODevice::WriteOnly ) )
        return false;

    QList<const GluonObject*> thisProject;
    thisProject.append( this );

    QTextStream projectWriter( &projectFile );
    projectWriter << GluonCore::GDLHandler::instance()->serializeGDL( thisProject );
    projectFile.close();

    QString projectDir = filename().toLocalFile().section( '/', 0, -2 );
    // Recreate the various icon files if we have an icon file available
    QImage icon(128, 128, QImage::Format_ARGB32);
    if( d->icon )
        icon = d->icon->texture()->image().scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    QString iconFile(projectDir);
    iconFile.append('/');
    iconFile.append( GluonEngine::projectIcon );
    icon.save( iconFile );
    if( QImageWriter::supportedImageFormats().contains("ico") )
    {
        iconFile = projectDir;
        iconFile.append('/');
        iconFile.append( GluonEngine::projectWinIcon );
        QImageWriter iconWriter(iconFile);
        iconWriter.setFormat("ico");
        iconWriter.write( icon );
    }

    // Build the folder information files for Windows and for XDG compliant file browsers
    QFile directoryFile( projectDir + "/.directory" );
    if( directoryFile.open( QFile::WriteOnly | QFile::Truncate | QIODevice::Text ) )
    {
        QTextStream out(&directoryFile);
        out << QString("[Desktop Entry]\nIcon=game.png\nType=Directory\n");
        directoryFile.close();
    }
    QFile folderFile( projectDir + "/desktop.ini" );
    if( folderFile.open( QFile::WriteOnly | QFile::Truncate | QIODevice::Text ) )
    {
        QTextStream out(&folderFile);
        out << QString("[.ShellClassInfo]\nConfirmFileOp=0\nIconFile=game.ico\nIconIndex=0\nInfoTip=A Gluon Game\n");
        folderFile.close();
    }

    // Recreate the screenshot file if we have one such
    if( d->screenshot )
    {
        QString screenshotFile = projectDir;
        screenshotFile.append('/');
        screenshotFile.append( GluonEngine::projectScreenshot );
        d->screenshot->texture()->image().scaled( 800, 600, Qt::KeepAspectRatio ).save( screenshotFile );
    }

    return true;
}

bool
GameProject::loadFromFile()
{
    DEBUG_FUNC_NAME

    // change directory to the project path..
    DEBUG_TEXT( QString( "Changing working directory to %1" ).arg( QFileInfo( filename().toLocalFile() ).canonicalPath() ) );
    QDir::setCurrent( QFileInfo( filename().toLocalFile() ).canonicalPath() );
    setFilename( filename().toLocalFile() );

    DEBUG_TEXT( QString( "Loading project from %1" ).arg( QFileInfo( filename().toLocalFile() ).fileName() ) );
    QFile projectFile( QFileInfo( filename().toLocalFile() ).fileName() );
    if( !projectFile.open( QIODevice::ReadOnly ) )
        return false;

    QTextStream projectReader( &projectFile );
    QString fileContents = projectReader.readAll();
    projectFile.close();

    if( fileContents.isEmpty() )
        return false;

    // Flush the script engine's module list. Otherwise we'll end up with state bits...
    // We do this here, since the GDL parser is likely to construct various objects which require
    // the scripting engine to be present. So, we clear it now, to be sure.
    GluonCore::ScriptEngine::instance()->resetEngine();

    QList<GluonObject*> objectList = GluonCore::GDLHandler::instance()->parseGDL( filename().toLocalFile(), parent() );
    if( objectList.count() > 0 )
    {
        if( objectList[0]->metaObject() )
        {
            // If the first object in the list is a GluonProject, then let's
            // adapt ourselves to represent that object...
            if( objectList[0]->metaObject()->className() == metaObject()->className() )
            {
                DEBUG_TEXT( "Project successfully parsed - applying to local instance" );
                GameProject* loadedProject = qobject_cast<GameProject*>( objectList[0] );

                // First things first - clean ourselves out, all the children
                // and the media info list should be gone-ified
                qDeleteAll( children() );

                // Reassign all the children of the newly loaded project to
                // ourselves...
                foreach( QObject * child, loadedProject->children() )
                {
                    GluonObject* theChild = qobject_cast<GluonObject*>( child );
                    theChild->setParent( this );
                    theChild->setGameProject( this );
                }

                // Set all the interesting values...
                setName( loadedProject->name() );

                // Copy across all the properties
                const QMetaObject* metaobject = loadedProject->metaObject();
                int count = metaobject->propertyCount();
                for( int i = 0; i < count; ++i )
                {
                    QMetaProperty metaproperty = metaobject->property( i );
                    const QString theName( metaproperty.name() );
                    if( theName == "objectName" || theName == "name" )
                        continue;
                    setProperty( metaproperty.name(), loadedProject->property( metaproperty.name() ) );
                }

                // Then get all the dynamic ones (in case any such exist)
                QList<QByteArray> propertyNames = loadedProject->dynamicPropertyNames();
                foreach( const QByteArray & propName, propertyNames )
                {
                    setProperty( propName, loadedProject->property( propName ) );
                }

                // Sanitize me!
                sanitize();

                // Finally, get rid of the left-overs
                qDeleteAll( objectList );

                DEBUG_TEXT( "Project loading successful!" );
            }
            // Otherwise it is not a GluonProject, and should fail!
            else
            {
                DEBUG_TEXT( QString( "First object loaded is not a Gluon::GameProject." ) );
                DEBUG_TEXT( QString( "Type of loaded object:" ).arg( objectList[0]->metaObject()->className() ) );
                DEBUG_TEXT( QString( "Name of loaded object:" ).arg( objectList[0]->name() ) );
                return false;
            }
        }
        else
        {
            return false;
        }
    }

    return true;
}

bool
GameProject::loadFromFile( QUrl fileUrl )
{
    setFilename( fileUrl );
    return loadFromFile();
}

bool
GameProject::loadFromFile( QString fileName )
{
    setFilename( fileName );
    return loadFromFile();
}

/******************************************************************************
 * Property Getter-setters
 *****************************************************************************/

QString
GameProject::description() const
{
    return d->description;
}

void
GameProject::setDescription( QString newDescription )
{
    d->description = newDescription;
}

QUrl
GameProject::homepage() const
{
    return d->homepage;
}
void
GameProject::setHomepage( QUrl newHomepage )
{
    d->homepage = newHomepage;
}

QList<QUrl>
GameProject::mediaInfo() const
{
    return d->mediaInfo;
}
void
GameProject::setMediaInfo( QList<QUrl> newMediaInfo )
{
    d->mediaInfo = newMediaInfo;
}

QUrl
GameProject::filename() const
{
    return d->filename;
}

void
GameProject::setFilename( QUrl fileUrl )
{
    d->filename = fileUrl;
}

void
GameProject::setFilename( QString fileName )
{
    d->filename = QUrl::fromLocalFile(fileName);
}

Scene *
GameProject::entryPoint() const
{
    return d->entryPoint;
}

void
GameProject::setEntryPoint( Scene* newEntryPoint )
{
    d->entryPoint = newEntryPoint;
}

GluonEngine::TextureAsset* GameProject::icon() const
{
    return d->icon;
}

void GameProject::setIcon(GluonEngine::TextureAsset* newIcon)
{
    d->icon = newIcon;
}

GluonEngine::TextureAsset* GameProject::screenshot() const
{
    return d->screenshot;
}

void GameProject::setScreenshot(GluonEngine::TextureAsset* newScreenshot)
{
    d->screenshot = newScreenshot;
}

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


<commit_before>#include <iostream>
#include <unistd.h>

int age = 23;

int main()
{
	sleep(2);
	std::cout << "I am Adrian.\n" << "Age: " << age << "\n";
	return 0;
}<commit_msg>Add newline at the end of the file<commit_after>#include <iostream>
#include <unistd.h>

int age = 23;

int main()
{
	sleep(2);
	std::cout << "I am Adrian.\n" << "Age: " << age << "\n";
	return 0;
}
<|endoftext|>


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

#include "md5sum.h"
#include <new>

#include <stdio.h>

using namespace org::w3c::dom;

void MD5SumInstance::initialize() {
  md5class = new (std::nothrow) MD5Class(this);
  if (md5class) {
    window->setElement("MD5", md5class);
  }
}

MD5SumInstance::~MD5SumInstance() {
  if (md5class) {
      md5class->release();
  }
}
<commit_msg>Clean up.<commit_after>/*
 * Copyright 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "md5sum.h"
#include <new>

using namespace org::w3c::dom;

void MD5SumInstance::initialize() {
  md5class = new (std::nothrow) MD5Class(this);
  if (md5class) {
    window->setElement("MD5", md5class);
  }
}

MD5SumInstance::~MD5SumInstance() {
  if (md5class) {
      md5class->release();
  }
}
<|endoftext|>


<commit_before>//                       MFEM Example normal-bc - Parallel Version
//

/*
  square-disc attributes (not indices):

  1: south external
  2: east external
  3: north external
  4: west external
  5: southeast internal
  6: northeast internal
  7: northwest internal
  8: southwest internal
*/

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

SparseMatrix * BuildConstraints(FiniteElementSpace& fespace, Array<int> constrained_att)
{
   int dim = fespace.GetVDim();

   std::set<int> constrained_dofs;
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         for (auto k : dofs)
         {
            constrained_dofs.insert(k);
         }
      }
   }

   std::map<int, int> dof_constraint;
   int n_constraints = 0;
   for (auto k : constrained_dofs)
   {
      dof_constraint[k] = n_constraints++;
   }
   SparseMatrix * out = new SparseMatrix(n_constraints, fespace.GetVSize());

   Vector nor(dim);
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         ElementTransformation * Tr = fespace.GetBdrElementTransformation(i);
         const FiniteElement * fe = fespace.GetBE(i);
         const IntegrationRule& nodes = fe->GetNodes();

         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         MFEM_VERIFY(dofs.Size() == nodes.Size(),
                     "Something wrong in finite element space!");

         for (int j = 0; j < dofs.Size(); ++j)
         {
            Tr->SetIntPoint(&nodes[j]);
            CalcOrtho(Tr->Jacobian(), nor); // this normal is scaled by h or something

            int k = dofs[j]; // are we sure nodes and dofs are ordered the same?
            int constraint = dof_constraint[k];
            for (int d = 0; d < dim; ++d)
            {
               int vdof = fespace.DofToVDof(k, d);
               out->Set(constraint, vdof, nor[d]);
            }
         }
      }
   }

   out->Finalize();
   return out;
}

class ConstrainedSolver : public Solver
{
public:
   ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B);
   ~ConstrainedSolver();

   void SetOperator(const Operator& op) { }

   void Mult(const Vector& b, Vector& x) const;

private:
   Array<int> offsets;
   BlockOperator * block_op;
   GMRESSolver gmres;
   TransposeOperator * tr_B;

   mutable Vector workb;
   mutable Vector workx;
};

ConstrainedSolver::ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B)
   :
   // Solver(A.Height() + B.Height()),
   Solver(A.Height()),  // not sure conceptually what the size should be!
   offsets(3),
   gmres(A.GetComm())
{
   offsets[0] = 0;
   offsets[1] = A.Height();
   offsets[2] = A.Height() + B.Height();

   block_op = new BlockOperator(offsets);
   block_op->SetBlock(0, 0, &A);
   block_op->SetBlock(1, 0, &B);
   tr_B = new TransposeOperator(&B);
   block_op->SetBlock(0, 1, tr_B);

   gmres.SetOperator(*block_op);
   gmres.SetRelTol(1.e-6);
   gmres.SetAbsTol(1.e-12);
   gmres.SetMaxIter(500);
   gmres.SetPrintLevel(1);

   workb.SetSize(A.Height() + B.Height());
   workx.SetSize(A.Height() + B.Height());
}

ConstrainedSolver::~ConstrainedSolver()
{
   delete block_op;
   delete tr_B;
}

void ConstrainedSolver::Mult(const Vector& b, Vector& x) const
{
   workb = 0.0;
   workx = 0.0;
   for (int i = 0; i < b.Size(); ++i)
   {
      workb(i) = b(i);
      workx(i) = x(i);
   }

   gmres.Mult(workb, workx);

   for (int i = 0; i < b.Size(); ++i)
   {
      x(i) = workx(i);
   }
}

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/square-disc.mesh";
   int order = 1;
   bool static_cond = false;
   bool pa = false;
   const char *device_config = "cpu";
   bool visualization = true;
   int boundary_attribute = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
                  "--no-partial-assembly", "Enable Partial Assembly.");
   args.AddOption(&device_config, "-d", "--device",
                  "Device configuration string, see Device::Configure().");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&boundary_attribute, "--boundary-attribute", "--boundary-attribute",
                  "Which attribute to apply essential conditions on.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   Device device(device_config);
   if (myid == 0) { device.Print(); }

   Mesh mesh(mesh_file, 1, 1);
   // mesh.EnsureNodes(); // ???
   int dim = mesh.Dimension();

   {
      int ref_levels =
         (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh.UniformRefinement();
      }
   }

   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   mesh.Clear();
   {
      // int par_ref_levels = 2;
      int par_ref_levels = 0;
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh.UniformRefinement();
      }
   }

   // 7. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   bool delete_fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
      delete_fec = true;
   }
   else if (pmesh.GetNodes())
   {
      fec = pmesh.GetNodes()->OwnFEC();
      delete_fec = false;
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
      delete_fec = true;
   }
   ParFiniteElementSpace fespace(&pmesh, fec, dim); // vector space
   HYPRE_Int size = fespace.GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   Array<int> ess_tdof_list;
   if (pmesh.bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh.bdr_attributes.Max());
      // ess_bdr = 1;
      ess_bdr = 0;
      ess_bdr[boundary_attribute - 1] = 1;
      fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   Array<int> circle_atts(4);
   circle_atts[0] = 5;
   circle_atts[1] = 6;
   circle_atts[2] = 7;
   circle_atts[3] = 8;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, circle_atts);
   {
      std::ofstream out("constraint.sparsematrix");
      constraint_mat->Print(out, 1);
   }

   ParLinearForm b(&fespace);
   // ConstantCoefficient one(1.0);
   Vector rhs_direction(dim);
   rhs_direction = 0.0;
   rhs_direction[0] = 1.0;
   VectorConstantCoefficient rhs_coeff(rhs_direction);
   b.AddDomainIntegrator(new VectorDomainLFIntegrator(rhs_coeff));
   b.Assemble();

   // 10. Define the solution vector x as a parallel finite element grid function
   //     corresponding to fespace. Initialize x with initial guess of zero,
   //     which satisfies the boundary conditions.
   ParGridFunction x(&fespace);
   x = 0.0;

   // 11. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm a(&fespace);
   if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
   // a.AddDomainIntegrator(new DiffusionIntegrator(one));
   Vector ones(dim);
   ones = 1.0;
   VectorConstantCoefficient coeff(ones);
   a.AddDomainIntegrator(new VectorMassIntegrator(coeff));

   // 12. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a.EnableStaticCondensation(); }
   a.Assemble();

   OperatorPtr A;
   Vector B, X;
   a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);

   ConstrainedSolver constrained(*A.As<HypreParMatrix>(), *constraint_mat);
   constrained.Mult(B, X);

/*
   // 13. Solve the linear system A X = B.
   //     * With full assembly, use the BoomerAMG preconditioner from hypre.
   //     * With partial assembly, use Jacobi smoothing, for now.
   Solver *prec = NULL;
   if (pa)
   {
      if (UsesTensorBasis(fespace))
      {
         prec = new OperatorJacobiSmoother(a, ess_tdof_list);
      }
   }
   else
   {
      auto h_prec = new HypreBoomerAMG;
      h_prec->SetPrintLevel(0);
      prec = h_prec;
   }
   CGSolver cg(MPI_COMM_WORLD);
   cg.SetRelTol(1e-12);
   cg.SetMaxIter(2000);
   cg.SetPrintLevel(1);
   if (prec) { cg.SetPreconditioner(*prec); }
   cg.SetOperator(*A);
   cg.Mult(B, X);
   delete prec;
*/

   // 14. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a.RecoverFEMSolution(X, b, x);

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      // todo: might make more sense to .SetCycle() than to append boundary_attribute to name
      std::stringstream visitname;
      visitname << "normal" << boundary_attribute;
      VisItDataCollection visit_dc(MPI_COMM_WORLD, visitname.str(), &pmesh);
      visit_dc.RegisterField("sol", &x);
      visit_dc.Save();
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << pmesh << x << flush;
   }

   // 17. Free the used memory.
   if (delete_fec)
   {
      delete fec;
   }
   delete constraint_mat;
   MPI_Finalize();

   return 0;
}
<commit_msg>ex-normal: seems to work fine in 3D<commit_after>//                       MFEM Example normal-bc - Parallel Version
//

/*
  higher order seems to work fine?
  3D also looks fine
  curved mesh does *not* seem to be working
  (not even for the mesh itself, but this may be VisIt and not MFEM)
  solver obviously still needs some serious work

  square-disc attributes (not indices):

  1: south external
  2: east external
  3: north external
  4: west external
  5: southeast internal
  6: northeast internal
  7: northwest internal
  8: southwest internal

  icf attributes (not indices):

  1: west side
  2: south side
  3: ???
  4: outer edge (circle constraint)
  5: some internal boundaries??

  sphere_hex27.mesh

  1: external boundary
*/

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

SparseMatrix * BuildConstraints(FiniteElementSpace& fespace, Array<int> constrained_att)
{
   int dim = fespace.GetVDim();

   std::set<int> constrained_dofs;
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         for (auto k : dofs)
         {
            constrained_dofs.insert(k);
         }
      }
   }

   std::map<int, int> dof_constraint;
   int n_constraints = 0;
   for (auto k : constrained_dofs)
   {
      dof_constraint[k] = n_constraints++;
   }
   SparseMatrix * out = new SparseMatrix(n_constraints, fespace.GetVSize());

   Vector nor(dim);
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         ElementTransformation * Tr = fespace.GetBdrElementTransformation(i);
         const FiniteElement * fe = fespace.GetBE(i);
         const IntegrationRule& nodes = fe->GetNodes();

         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         MFEM_VERIFY(dofs.Size() == nodes.Size(),
                     "Something wrong in finite element space!");

         for (int j = 0; j < dofs.Size(); ++j)
         {
            Tr->SetIntPoint(&nodes[j]);
            CalcOrtho(Tr->Jacobian(), nor); // this normal is scaled by h or something

            int k = dofs[j]; // are we sure nodes and dofs are ordered the same?
            int constraint = dof_constraint[k];
            for (int d = 0; d < dim; ++d)
            {
               int vdof = fespace.DofToVDof(k, d);
               out->Set(constraint, vdof, nor[d]);
            }
         }
      }
   }

   out->Finalize();
   return out;
}

class ConstrainedSolver : public Solver
{
public:
   ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B);
   ~ConstrainedSolver();

   void SetOperator(const Operator& op) { }

   void Mult(const Vector& b, Vector& x) const;

private:
   Array<int> offsets;
   BlockOperator * block_op;
   GMRESSolver gmres;
   TransposeOperator * tr_B;

   mutable Vector workb;
   mutable Vector workx;
};

ConstrainedSolver::ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B)
   :
   // Solver(A.Height() + B.Height()),
   Solver(A.Height()),  // not sure conceptually what the size should be!
   offsets(3),
   gmres(A.GetComm())
{
   offsets[0] = 0;
   offsets[1] = A.Height();
   offsets[2] = A.Height() + B.Height();

   block_op = new BlockOperator(offsets);
   block_op->SetBlock(0, 0, &A);
   block_op->SetBlock(1, 0, &B);
   tr_B = new TransposeOperator(&B);
   block_op->SetBlock(0, 1, tr_B);

   gmres.SetOperator(*block_op);
   gmres.SetRelTol(1.e-6);
   gmres.SetAbsTol(1.e-12);
   gmres.SetMaxIter(500);
   gmres.SetPrintLevel(1);

   workb.SetSize(A.Height() + B.Height());
   workx.SetSize(A.Height() + B.Height());
}

ConstrainedSolver::~ConstrainedSolver()
{
   delete block_op;
   delete tr_B;
}

void ConstrainedSolver::Mult(const Vector& b, Vector& x) const
{
   workb = 0.0;
   workx = 0.0;
   for (int i = 0; i < b.Size(); ++i)
   {
      workb(i) = b(i);
      workx(i) = x(i);
   }

   gmres.Mult(workb, workx);

   for (int i = 0; i < b.Size(); ++i)
   {
      x(i) = workx(i);
   }
}

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/square-disc-p3.mesh";
   int order = 1;
   bool static_cond = false;
   bool pa = false;
   const char *device_config = "cpu";
   bool visualization = true;
   int boundary_attribute = 0;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
                  "--no-partial-assembly", "Enable Partial Assembly.");
   args.AddOption(&device_config, "-d", "--device",
                  "Device configuration string, see Device::Configure().");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&boundary_attribute, "--boundary-attribute", "--boundary-attribute",
                  "Which attribute to apply essential conditions on.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   Device device(device_config);
   if (myid == 0) { device.Print(); }

   Mesh mesh(mesh_file, 1, 1);
   // mesh.EnsureNodes(); // ???
   int dim = mesh.Dimension();

   {
      int ref_levels =
         (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh.UniformRefinement();
      }
   }
   mesh.SetCurvature(order); // ??? try to get curved mesh

   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   mesh.Clear();
   {
      // int par_ref_levels = 2;
      int par_ref_levels = 0;
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh.UniformRefinement();
      }
   }

   // 7. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   bool delete_fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
      delete_fec = true;
   }
   else if (pmesh.GetNodes())
   {
      fec = pmesh.GetNodes()->OwnFEC();
      delete_fec = false;
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
      delete_fec = true;
   }
   ParFiniteElementSpace fespace(&pmesh, fec, dim); // vector space
   HYPRE_Int size = fespace.GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   Array<int> ess_tdof_list;
   if (pmesh.bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh.bdr_attributes.Max());
      // ess_bdr = 1;
      ess_bdr = 0;
      if (boundary_attribute > 0)
      {
         ess_bdr[boundary_attribute - 1] = 1;
      }
      fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

/*
   Array<int> circle_atts(4);
   circle_atts[0] = 5;
   circle_atts[1] = 6;
   circle_atts[2] = 7;
   circle_atts[3] = 8;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, circle_atts);
*/

/*
   Array<int> icf_atts(1);
   icf_atts[0] = 4;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, icf_atts);
*/

   Array<int> sphere_atts(1);
   sphere_atts[0] = 1;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, sphere_atts);

   {
      std::ofstream out("constraint.sparsematrix");
      constraint_mat->Print(out, 1);
   }

   ParLinearForm b(&fespace);
   // ConstantCoefficient one(1.0);
   Vector rhs_direction(dim);
   rhs_direction = 0.0;
   rhs_direction[0] = 1.0;
   VectorConstantCoefficient rhs_coeff(rhs_direction);
   b.AddDomainIntegrator(new VectorDomainLFIntegrator(rhs_coeff));
   b.Assemble();

   // 10. Define the solution vector x as a parallel finite element grid function
   //     corresponding to fespace. Initialize x with initial guess of zero,
   //     which satisfies the boundary conditions.
   ParGridFunction x(&fespace);
   x = 0.0;

   // 11. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm a(&fespace);
   if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
   // a.AddDomainIntegrator(new DiffusionIntegrator(one));
   Vector ones(dim);
   ones = 1.0;
   VectorConstantCoefficient coeff(ones);
   a.AddDomainIntegrator(new VectorMassIntegrator(coeff));

   // 12. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a.EnableStaticCondensation(); }
   a.Assemble();

   OperatorPtr A;
   Vector B, X;
   a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);

   ConstrainedSolver constrained(*A.As<HypreParMatrix>(), *constraint_mat);
   constrained.Mult(B, X);

   // 14. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a.RecoverFEMSolution(X, b, x);

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      // todo: might make more sense to .SetCycle() than to append boundary_attribute to name
      std::stringstream visitname;
      visitname << "normal" << boundary_attribute;
      // visitname << "icf";
      VisItDataCollection visit_dc(MPI_COMM_WORLD, visitname.str(), &pmesh);
      visit_dc.SetLevelsOfDetail(4);
      visit_dc.RegisterField("sol", &x);
      // visit_dc.SetCycle(boundary_attribute);
      visit_dc.Save();
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << pmesh << x << flush;
   }

   // 17. Free the used memory.
   if (delete_fec)
   {
      delete fec;
   }
   delete constraint_mat;
   MPI_Finalize();

   return 0;
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "Moka.h"

TEST(TestMoka, States) {
    using namespace antoniocoratelli::moka;

    // Verifying which controllable events are enabled for each state.
    EXPECT_EQ(true,  StateIdle().triggers<EventFillWater>());
    EXPECT_EQ(false, StateIdle().triggers<EventClean>());
    EXPECT_EQ(false, StateWaitingForGroundCoffee().triggers<EventFillWater>());
    EXPECT_EQ(true,  StateWaitingForGroundCoffee().triggers<EventClean>());
    EXPECT_EQ(true,  StateReadyToBrew().triggers<EventClean>());
    EXPECT_EQ(true,  StateReadyToBrew().triggers<EventTurnFireOn>());
    EXPECT_EQ(false, StateReadyToBrew().triggers<EventTurnFireOff>());
    EXPECT_EQ(true,  StateBrewing().triggers<EventTurnFireOff>());
    EXPECT_EQ(false, StateBrewing().triggers<EventTurnFireOn>());
    EXPECT_EQ(true,  StateDirty().triggers<EventClean>());
    EXPECT_EQ(false, StateDirty().triggers<EventServe>());
    EXPECT_EQ(true,  StateReadyToServe().triggers<EventServe>());
    EXPECT_EQ(false, StateReadyToServe().triggers<EventFillWater>());
}

<commit_msg>Add Moka test for nominal usage<commit_after>#include <gtest/gtest.h>
#include "Moka.h"

TEST(TestMoka, States) {
    using namespace antoniocoratelli::moka;

    // Verifying which controllable events are enabled for each state.
    EXPECT_EQ(true,  StateIdle().triggers<EventFillWater>());
    EXPECT_EQ(false, StateIdle().triggers<EventClean>());
    EXPECT_EQ(false, StateWaitingForGroundCoffee().triggers<EventFillWater>());
    EXPECT_EQ(true,  StateWaitingForGroundCoffee().triggers<EventClean>());
    EXPECT_EQ(true,  StateReadyToBrew().triggers<EventClean>());
    EXPECT_EQ(true,  StateReadyToBrew().triggers<EventTurnFireOn>());
    EXPECT_EQ(false, StateReadyToBrew().triggers<EventTurnFireOff>());
    EXPECT_EQ(true,  StateBrewing().triggers<EventTurnFireOff>());
    EXPECT_EQ(false, StateBrewing().triggers<EventTurnFireOn>());
    EXPECT_EQ(true,  StateDirty().triggers<EventClean>());
    EXPECT_EQ(false, StateDirty().triggers<EventServe>());
    EXPECT_EQ(true,  StateReadyToServe().triggers<EventServe>());
    EXPECT_EQ(false, StateReadyToServe().triggers<EventFillWater>());
}

TEST(TestMoka, NormalUsage) {
    using namespace antoniocoratelli::moka;

    // Initializing the moka: it's Idle by default.
    Moka moka;
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateIdle>());

    // Filling water.
    EXPECT_NO_THROW(moka.trigger<EventFillWater>());
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateWaitingForGroundCoffee>());

    // Adding ground coffee.
    EXPECT_NO_THROW(moka.trigger<EventPutGroundCoffee>());
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateReadyToBrew>());

    // Turning fire on.
    EXPECT_NO_THROW(moka.trigger<EventTurnFireOn>());
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateBrewing>());

    // Waiting for it to finish.
    while(not moka.update())
        std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateReadyToServe>());

    // Serving.
    EXPECT_NO_THROW(moka.trigger<EventServe>());
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateDirty>());

    // Cleaning.
    EXPECT_NO_THROW(moka.trigger<EventClean>());
    std::cout << moka.info() << std::endl;
    EXPECT_EQ(true, moka.in<StateIdle>());
}
<|endoftext|>