<commit_before>/*
   This file is part of INDDGO.

   Copyright (C) 2012, Oak Ridge National Laboratory

   This product includes software produced by UT-Battelle, LLC under Contract No.
   DE-AC05-00OR22725 with the Department of Energy.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the New BSD 3-clause software license (LICENSE).

   This program 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
   LICENSE for more details.

   For more information please contact the INDDGO developers at:
   inddgo-info@googlegroups.com

 */

#include "GraphDecomposition.h"
#include "GraphProperties.h"
#include "Log.h"
#include "VertexWeightedGraph.h"
#include "GraphException.h"
#include "GraphReader.h"
#include "GraphWriter.h"
#include <numeric>
#include <ctime>
#include <sys/time.h>
#include <stdint.h>

using namespace std;

void usage(const char *s){
    fprintf(stderr,"Usage: %s filename\n",s);
}

uint64_t diff_timeval(struct timeval begin, struct timeval end){
    uint64_t begin_us, end_us;

    begin_us = begin.tv_usec + 100000*begin.tv_sec;
    end_us = end.tv_usec + 100000*end.tv_sec;
    return (end_us - begin_us);
}

int main(int argc, char **argv){
    // Check for a cry for help
    if((argc == 1) || ((argc == 2) && (strcmp(argv[1],"-h") == 0)) || ((argc == 2) && (strcmp(argv[1],"--help") == 0))
       || ((argc == 2) && (strcmp(argv[1],"--h") == 0) ) ){
        usage(argv[0]);
        exit(-1);
    }

    Graph::Graph *g;
    int seed = 0;
    int sum;

    clock_t begin, end;
    struct timeval t1, t2;
    uint64_t elapsed;

    Graph::GraphProperties prop;
    Graph::GraphReader ngr;

    // Create the graph object
    g = new Graph::Graph();

    // read the graph from the filename, assume it is an edgelist
    ngr.read_graph(g, argv[1], "Edge", false);
    printf("Read %d vertices and %d edges\n", g->get_num_nodes(), g->get_num_edges());

    printf("Simplifying graph\n");
    begin = clock();
    gettimeofday(&t1, NULL);
    prop.make_simple(g);
    gettimeofday(&t2, NULL);
    end = clock();
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);
    printf("Time (gt): %lf\n", diff_timeval(t1, t2) / 100000.0);
    printf("After simplification: %d vertices and %d edges\n", g->get_num_nodes(), g->get_num_edges());

    //Now, do our calculations
    vector<long int> triangles(g->get_num_nodes(), 0);

    printf("Calculating triangles using compact-forward method\n");
    begin = clock();
    prop.all_triangles_compact_forward(g, triangles);
    end = clock();
    sum = std::accumulate(triangles.begin(), triangles.end(), 0);
    printf("Total triangles (compact-forward): %d\n", sum);
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);

    /*
    triangles.assign(g->get_num_nodes(), 0);
    printf("Calculating triangles using edge-listing method\n");
    begin = clock();
    prop.all_triangles_edge_listing(g, triangles);
    end = clock();
    sum = std::accumulate(triangles.begin(), triangles.end(), 0);
    printf("Total triangles (edge-listing): %d (%d)\n", sum / 3, sum);
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);
*/
   // double g_cc, a_cc;
  //  vector<double> l_cc;
  //  prop.clustering_coefficients(g, g_cc, a_cc, l_cc);

 //   printf("Local CCs:");
  //  int i;
//    for(i = 0; i < g->get_num_nodes(); i++){
 //     printf(" %d:%lf",i,l_cc[i]);
//    }
//   printf("\n");

  //  printf("Global cc: %lf\nAvg cc: %lf", g_cc, a_cc);

    delete g;

    return 0;
} // main

<commit_msg>add another gettimeofday calculation<commit_after>/*
   This file is part of INDDGO.

   Copyright (C) 2012, Oak Ridge National Laboratory

   This product includes software produced by UT-Battelle, LLC under Contract No.
   DE-AC05-00OR22725 with the Department of Energy.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the New BSD 3-clause software license (LICENSE).

   This program 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
   LICENSE for more details.

   For more information please contact the INDDGO developers at:
   inddgo-info@googlegroups.com

 */

#include "GraphDecomposition.h"
#include "GraphProperties.h"
#include "Log.h"
#include "VertexWeightedGraph.h"
#include "GraphException.h"
#include "GraphReader.h"
#include "GraphWriter.h"
#include <numeric>
#include <ctime>
#include <sys/time.h>
#include <stdint.h>

using namespace std;

void usage(const char *s){
    fprintf(stderr,"Usage: %s filename\n",s);
}

uint64_t diff_timeval(struct timeval begin, struct timeval end){
    uint64_t begin_us, end_us;

    begin_us = begin.tv_usec + 100000*begin.tv_sec;
    end_us = end.tv_usec + 100000*end.tv_sec;
    return (end_us - begin_us);
}

int main(int argc, char **argv){
    // Check for a cry for help
    if((argc == 1) || ((argc == 2) && (strcmp(argv[1],"-h") == 0)) || ((argc == 2) && (strcmp(argv[1],"--help") == 0))
       || ((argc == 2) && (strcmp(argv[1],"--h") == 0) ) ){
        usage(argv[0]);
        exit(-1);
    }

    Graph::Graph *g;
    int seed = 0;
    int sum;

    clock_t begin, end;
    struct timeval t1, t2;
    uint64_t elapsed;

    Graph::GraphProperties prop;
    Graph::GraphReader ngr;

    // Create the graph object
    g = new Graph::Graph();

    // read the graph from the filename, assume it is an edgelist
    ngr.read_graph(g, argv[1], "Edge", false);
    printf("Read %d vertices and %d edges\n", g->get_num_nodes(), g->get_num_edges());

    printf("Simplifying graph\n");
    begin = clock();
    gettimeofday(&t1, NULL);
    prop.make_simple(g);
    gettimeofday(&t2, NULL);
    end = clock();
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);
    printf("Time (gt): %lf\n", diff_timeval(t1, t2) / 100000.0);
    printf("After simplification: %d vertices and %d edges\n", g->get_num_nodes(), g->get_num_edges());

    //Now, do our calculations
    vector<long int> triangles(g->get_num_nodes(), 0);

    printf("Calculating triangles using compact-forward method\n");
    begin = clock();
    gettimeofday(&t1, NULL);
    prop.all_triangles_compact_forward(g, triangles);
    gettimeofday(&t2, NULL);
    end = clock();
    sum = std::accumulate(triangles.begin(), triangles.end(), 0);
    printf("Total triangles (compact-forward): %d\n", sum);
    printf("Time (gt): %lf\n", diff_timeval(t1, t2) / 100000.0);
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);

    /*
    triangles.assign(g->get_num_nodes(), 0);
    printf("Calculating triangles using edge-listing method\n");
    begin = clock();
    prop.all_triangles_edge_listing(g, triangles);
    end = clock();
    sum = std::accumulate(triangles.begin(), triangles.end(), 0);
    printf("Total triangles (edge-listing): %d (%d)\n", sum / 3, sum);
    printf("Time: %lf\n", double(end - begin) / CLOCKS_PER_SEC);
*/
   // double g_cc, a_cc;
  //  vector<double> l_cc;
  //  prop.clustering_coefficients(g, g_cc, a_cc, l_cc);

 //   printf("Local CCs:");
  //  int i;
//    for(i = 0; i < g->get_num_nodes(); i++){
 //     printf(" %d:%lf",i,l_cc[i]);
//    }
//   printf("\n");

  //  printf("Global cc: %lf\nAvg cc: %lf", g_cc, a_cc);

    delete g;

    return 0;
} // main

<|endoftext|>


<commit_before>/***************************************************************************
 *  algo/async_schedule.cpp
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2002, 2009 Roman Dementiev <dementiev@mpi-sb.mpg.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

// Implements the "prudent prefetching" as described in
// D. Hutchinson, P. Sanders, J. S. Vitter: Duality between prefetching
// and queued writing on parallel disks, 2005
// DOI: 10.1137/S0097539703431573

#include <stxxl/bits/algo/async_schedule.h>
#include <stxxl/bits/verbose.h>

#include <algorithm>
#include <functional>
#include <queue>
#include <cassert>

__STXXL_BEGIN_NAMESPACE

namespace async_schedule_local
{
    struct sim_event  // only one type of event: WRITE COMPLETED
    {
        int_type timestamp;
        int_type iblock;
        inline sim_event(int_type t, int_type b) : timestamp(t), iblock(b) { }
    };

    struct sim_event_cmp : public std::binary_function<sim_event, sim_event, bool>
    {
        inline bool operator () (const sim_event & a, const sim_event & b) const
        {
            return a.timestamp > b.timestamp;
        }
    };

    typedef std::pair<int_type, int_type> write_time_pair;
    struct write_time_cmp : public std::binary_function<write_time_pair, write_time_pair, bool>
    {
        inline bool operator () (const write_time_pair & a, const write_time_pair & b) const
        {
            return a.second > b.second;
        }
    };

    int_type simulate_async_write(
        const int_type * disks,
        const int_type L,
        const int_type m_init,
        const int_type D,
        std::pair<int_type, int_type> * o_time)
    {
        typedef std::priority_queue<sim_event, std::vector<sim_event>, sim_event_cmp> event_queue_type;
        typedef std::queue<int_type> disk_queue_type;
        assert(L >= D);
        disk_queue_type * disk_queues = new disk_queue_type[D];
        event_queue_type event_queue;

        int_type m = m_init;
        int_type i = L - 1;
        int_type oldtime = 0;
        bool * disk_busy = new bool[D];

        while (m && (i >= 0))
        {
            int_type disk = disks[i];
            assert(0 <= disk && disk < D);
            disk_queues[disk].push(i);
            i--;
            m--;
        }

        for (int_type ii = 0; ii < D; ii++)
            if (!disk_queues[ii].empty())
            {
                int_type j = disk_queues[ii].front();
                disk_queues[ii].pop();
                event_queue.push(sim_event(1, j));
                //STXXL_MSG("Block "<<j<<" scheduled");
            }

        while (!event_queue.empty())
        {
            sim_event cur = event_queue.top();
            event_queue.pop();
            if (oldtime != cur.timestamp)
            {
                // clear disk_busy
                for (int_type i = 0; i < D; i++)
                    disk_busy[i] = false;

                oldtime = cur.timestamp;
            }

            STXXL_VERBOSE1("Block " << cur.iblock << " put out, time " << cur.timestamp << " disk: " << disks[cur.iblock]);
            o_time[cur.iblock] = std::pair<int_type, int_type>(cur.iblock, cur.timestamp);

            if (i >= 0)
            {
                int_type disk = disks[i];
                assert(0 <= disk && disk < D);
                if (disk_busy[disk])
                {
                    disk_queues[disk].push(i--);
                }
                else
                {
                    if (!disk_queues[disk].empty())
                    {
                        STXXL_VERBOSE1("c Block " << disk_queues[disk].front() << " scheduled for time " << cur.timestamp + 1);
                        event_queue.push(sim_event(cur.timestamp + 1, disk_queues[disk].front()));
                        disk_queues[disk].pop();
                    } else
                    {
                        STXXL_VERBOSE1("a Block " << i << " scheduled for time " << cur.timestamp + 1);
                        event_queue.push(sim_event(cur.timestamp + 1, i--));
                    }
                    disk_busy[disk] = true;
                }
            }

            // add next block to write
            int_type disk = disks[cur.iblock];
            assert(0 <= disk && disk < D);
            if (!disk_busy[disk] && !disk_queues[disk].empty())
            {
                STXXL_VERBOSE1("b Block " << disk_queues[disk].front() << " scheduled for time " << cur.timestamp + 1);
                event_queue.push(sim_event(cur.timestamp + 1, disk_queues[disk].front()));
                disk_queues[disk].pop();
                disk_busy[disk] = true;
            }
        }

        assert(i == -1);
        for (int_type i = 0; i < D; i++)
            assert(disk_queues[i].empty());

        delete[] disk_busy;
        delete[] disk_queues;

        return (oldtime - 1);
    }
}  // namespace async_schedule_local

void compute_prefetch_schedule(
    const int_type * first,
    const int_type * last,
    int_type * out_first,
    int_type m,
    int_type D)
{
    typedef std::pair<int_type, int_type> pair_type;
    int_type L = last - first;
    if (L <= D)
    {
        for (int_type i = 0; i < L; ++i)
            out_first[i] = i;

        return;
    }
    pair_type * write_order = new pair_type[L];

    int_type w_steps = async_schedule_local::simulate_async_write(first, L, m, D, write_order);

    STXXL_VERBOSE1("Write steps: " << w_steps);

    for (int_type i = 0; i < L; i++)
        STXXL_VERBOSE1(first[i] << " " << write_order[i].first << " " << write_order[i].second);

    std::stable_sort(write_order, write_order + L, async_schedule_local::write_time_cmp());

    for (int_type i = 0; i < L; i++)
    {
        out_first[i] = write_order[i].first;
        //if(out_first[i] != i)
        STXXL_VERBOSE1(i << " " << out_first[i]);
    }

    delete[] write_order;
    STXXL_UNUSED(w_steps);
}

__STXXL_END_NAMESPACE

// vim: et:ts=4:sw=4
<commit_msg>use _FORCE_SEQUENTIAL to avoid libgomp dependency in the library<commit_after>/***************************************************************************
 *  algo/async_schedule.cpp
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2002, 2009 Roman Dementiev <dementiev@mpi-sb.mpg.de>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

// Implements the "prudent prefetching" as described in
// D. Hutchinson, P. Sanders, J. S. Vitter: Duality between prefetching
// and queued writing on parallel disks, 2005
// DOI: 10.1137/S0097539703431573

#include <stxxl/bits/algo/async_schedule.h>
#include <stxxl/bits/verbose.h>
#include <stxxl/bits/parallel.h>

#include <algorithm>
#include <functional>
#include <queue>
#include <cassert>

__STXXL_BEGIN_NAMESPACE

namespace async_schedule_local
{
    struct sim_event  // only one type of event: WRITE COMPLETED
    {
        int_type timestamp;
        int_type iblock;
        inline sim_event(int_type t, int_type b) : timestamp(t), iblock(b) { }
    };

    struct sim_event_cmp : public std::binary_function<sim_event, sim_event, bool>
    {
        inline bool operator () (const sim_event & a, const sim_event & b) const
        {
            return a.timestamp > b.timestamp;
        }
    };

    typedef std::pair<int_type, int_type> write_time_pair;
    struct write_time_cmp : public std::binary_function<write_time_pair, write_time_pair, bool>
    {
        inline bool operator () (const write_time_pair & a, const write_time_pair & b) const
        {
            return a.second > b.second;
        }
    };

    int_type simulate_async_write(
        const int_type * disks,
        const int_type L,
        const int_type m_init,
        const int_type D,
        std::pair<int_type, int_type> * o_time)
    {
        typedef std::priority_queue<sim_event, std::vector<sim_event>, sim_event_cmp> event_queue_type;
        typedef std::queue<int_type> disk_queue_type;
        assert(L >= D);
        disk_queue_type * disk_queues = new disk_queue_type[D];
        event_queue_type event_queue;

        int_type m = m_init;
        int_type i = L - 1;
        int_type oldtime = 0;
        bool * disk_busy = new bool[D];

        while (m && (i >= 0))
        {
            int_type disk = disks[i];
            assert(0 <= disk && disk < D);
            disk_queues[disk].push(i);
            i--;
            m--;
        }

        for (int_type ii = 0; ii < D; ii++)
            if (!disk_queues[ii].empty())
            {
                int_type j = disk_queues[ii].front();
                disk_queues[ii].pop();
                event_queue.push(sim_event(1, j));
                //STXXL_MSG("Block "<<j<<" scheduled");
            }

        while (!event_queue.empty())
        {
            sim_event cur = event_queue.top();
            event_queue.pop();
            if (oldtime != cur.timestamp)
            {
                // clear disk_busy
                for (int_type i = 0; i < D; i++)
                    disk_busy[i] = false;

                oldtime = cur.timestamp;
            }

            STXXL_VERBOSE1("Block " << cur.iblock << " put out, time " << cur.timestamp << " disk: " << disks[cur.iblock]);
            o_time[cur.iblock] = std::pair<int_type, int_type>(cur.iblock, cur.timestamp);

            if (i >= 0)
            {
                int_type disk = disks[i];
                assert(0 <= disk && disk < D);
                if (disk_busy[disk])
                {
                    disk_queues[disk].push(i--);
                }
                else
                {
                    if (!disk_queues[disk].empty())
                    {
                        STXXL_VERBOSE1("c Block " << disk_queues[disk].front() << " scheduled for time " << cur.timestamp + 1);
                        event_queue.push(sim_event(cur.timestamp + 1, disk_queues[disk].front()));
                        disk_queues[disk].pop();
                    } else
                    {
                        STXXL_VERBOSE1("a Block " << i << " scheduled for time " << cur.timestamp + 1);
                        event_queue.push(sim_event(cur.timestamp + 1, i--));
                    }
                    disk_busy[disk] = true;
                }
            }

            // add next block to write
            int_type disk = disks[cur.iblock];
            assert(0 <= disk && disk < D);
            if (!disk_busy[disk] && !disk_queues[disk].empty())
            {
                STXXL_VERBOSE1("b Block " << disk_queues[disk].front() << " scheduled for time " << cur.timestamp + 1);
                event_queue.push(sim_event(cur.timestamp + 1, disk_queues[disk].front()));
                disk_queues[disk].pop();
                disk_busy[disk] = true;
            }
        }

        assert(i == -1);
        for (int_type i = 0; i < D; i++)
            assert(disk_queues[i].empty());

        delete[] disk_busy;
        delete[] disk_queues;

        return (oldtime - 1);
    }
}  // namespace async_schedule_local

void compute_prefetch_schedule(
    const int_type * first,
    const int_type * last,
    int_type * out_first,
    int_type m,
    int_type D)
{
    typedef std::pair<int_type, int_type> pair_type;
    int_type L = last - first;
    if (L <= D)
    {
        for (int_type i = 0; i < L; ++i)
            out_first[i] = i;

        return;
    }
    pair_type * write_order = new pair_type[L];

    int_type w_steps = async_schedule_local::simulate_async_write(first, L, m, D, write_order);

    STXXL_VERBOSE1("Write steps: " << w_steps);

    for (int_type i = 0; i < L; i++)
        STXXL_VERBOSE1(first[i] << " " << write_order[i].first << " " << write_order[i].second);

    std::stable_sort(write_order, write_order + L, async_schedule_local::write_time_cmp() _STXXL_FORCE_SEQUENTIAL);

    for (int_type i = 0; i < L; i++)
    {
        out_first[i] = write_order[i].first;
        //if(out_first[i] != i)
        STXXL_VERBOSE1(i << " " << out_first[i]);
    }

    delete[] write_order;
    STXXL_UNUSED(w_steps);
}

__STXXL_END_NAMESPACE

// vim: et:ts=4:sw=4
<|endoftext|>


<commit_before>
/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <stdint.h>
#include <memory>
#include "bytes.hh"
#include "utils/allocation_strategy.hh"
#include <seastar/core/unaligned.hh>
#include <seastar/util/alloc_failure_injector.hh>
#include <unordered_map>
#include <type_traits>

struct blob_storage {
    struct [[gnu::packed]] ref_type {
        blob_storage* ptr;

        ref_type() {}
        ref_type(blob_storage* ptr) : ptr(ptr) {}
        operator blob_storage*() const { return ptr; }
        blob_storage* operator->() const { return ptr; }
        blob_storage& operator*() const { return *ptr; }
    };
    using size_type = uint32_t;
    using char_type = bytes_view::value_type;

    ref_type* backref;
    size_type size;
    size_type frag_size;
    ref_type next;
    char_type data[];

    blob_storage(ref_type* backref, size_type size, size_type frag_size) noexcept
        : backref(backref)
        , size(size)
        , frag_size(frag_size)
        , next(nullptr)
    {
        *backref = this;
    }

    blob_storage(blob_storage&& o) noexcept
        : backref(o.backref)
        , size(o.size)
        , frag_size(o.frag_size)
        , next(o.next)
    {
        *backref = this;
        o.next = nullptr;
        if (next) {
            next->backref = &next;
        }
        memcpy(data, o.data, frag_size);
    }
} __attribute__((packed));

// A managed version of "bytes" (can be used with LSA).
class managed_bytes {
    static thread_local std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>> _lc_state;
    struct linearization_context {
        unsigned _nesting = 0;
        // Map from first blob_storage address to linearized version
        // We use the blob_storage address to be insentive to moving
        // a managed_bytes object.
        // linearization_context is entered often in the fast path, but it is
        // actually used only in rare (slow) cases.
        std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>>* _state_ptr = nullptr;
        void enter() {
            ++_nesting;
        }
        void leave() {
            if (!--_nesting && _state_ptr) {
                _state_ptr->clear();
                _state_ptr = nullptr;
            }
        }
        void forget(const blob_storage* p) noexcept;
    };
    static thread_local linearization_context _linearization_context;
public:
    struct linearization_context_guard {
        linearization_context_guard() {
            _linearization_context.enter();
        }
        ~linearization_context_guard() {
            _linearization_context.leave();
        }
    };
private:
    static constexpr size_t max_inline_size = 15;
    struct small_blob {
        bytes_view::value_type data[max_inline_size];
        int8_t size; // -1 -> use blob_storage
    };
    union u {
        u() {}
        ~u() {}
        blob_storage::ref_type ptr;
        small_blob small;
    } _u;
    static_assert(sizeof(small_blob) > sizeof(blob_storage*), "inline size too small");
private:
    bool external() const {
        return _u.small.size < 0;
    }
    size_t max_seg(allocation_strategy& alctr) {
        return alctr.preferred_max_contiguous_allocation() - sizeof(blob_storage);
    }
    void free_chain(blob_storage* p) noexcept {
        if (p->next && _linearization_context._nesting) {
            _linearization_context.forget(p);
        }
        auto& alctr = current_allocator();
        while (p) {
            auto n = p->next;
            alctr.destroy(p);
            p = n;
        }
    }
    const bytes_view::value_type* read_linearize() const {
        if (!external()) {
            return _u.small.data;
        } else  if (!_u.ptr->next) {
            return _u.ptr->data;
        } else {
            return do_linearize();
        }
    }
    bytes_view::value_type& value_at_index(blob_storage::size_type index) {
        if (!external()) {
            return _u.small.data[index];
        }
        blob_storage* a = _u.ptr;
        while (index >= a->frag_size) {
            index -= a->frag_size;
            a = a->next;
        }
        return a->data[index];
    }
    const bytes_view::value_type* do_linearize() const;
public:
    using size_type = blob_storage::size_type;
    struct initialized_later {};

    managed_bytes() {
        _u.small.size = 0;
    }

    managed_bytes(const blob_storage::char_type* ptr, size_type size)
        : managed_bytes(bytes_view(ptr, size)) {}

    managed_bytes(const bytes& b) : managed_bytes(static_cast<bytes_view>(b)) {}

    managed_bytes(initialized_later, size_type size) {
        memory::on_alloc_point();
        if (size <= max_inline_size) {
            _u.small.size = size;
        } else {
            _u.small.size = -1;
            auto& alctr = current_allocator();
            auto maxseg = max_seg(alctr);
            auto now = std::min(size_t(size), maxseg);
            void* p = alctr.alloc(&get_standard_migrator<blob_storage>(),
                sizeof(blob_storage) + now, alignof(blob_storage));
            auto first = new (p) blob_storage(&_u.ptr, size, now);
            auto last = first;
            size -= now;
            try {
                while (size) {
                    auto now = std::min(size_t(size), maxseg);
                    void* p = alctr.alloc(&get_standard_migrator<blob_storage>(),
                        sizeof(blob_storage) + now, alignof(blob_storage));
                    last = new (p) blob_storage(&last->next, 0, now);
                    size -= now;
                }
            } catch (...) {
                free_chain(first);
                throw;
            }
        }
    }

    managed_bytes(bytes_view v) : managed_bytes(initialized_later(), v.size()) {
        if (!external()) {
            std::copy(v.begin(), v.end(), _u.small.data);
            return;
        }
        auto p = v.data();
        auto s = v.size();
        auto b = _u.ptr;
        while (s) {
            memcpy(b->data, p, b->frag_size);
            p += b->frag_size;
            s -= b->frag_size;
            b = b->next;
        }
        assert(!b);
    }

    managed_bytes(std::initializer_list<bytes::value_type> b) : managed_bytes(b.begin(), b.size()) {}

    ~managed_bytes() noexcept {
        if (external()) {
            free_chain(_u.ptr);
        }
    }

    managed_bytes(const managed_bytes& o) : managed_bytes(initialized_later(), o.size()) {
        if (!external()) {
            memcpy(data(), o.data(), size());
            return;
        }
        auto s = size();
        const blob_storage::ref_type* next_src = &o._u.ptr;
        blob_storage* blob_src = nullptr;
        size_type size_src = 0;
        size_type offs_src = 0;
        blob_storage::ref_type* next_dst = &_u.ptr;
        blob_storage* blob_dst = nullptr;
        size_type size_dst = 0;
        size_type offs_dst = 0;
        while (s) {
            if (!size_src) {
                blob_src = *next_src;
                next_src = &blob_src->next;
                size_src = blob_src->frag_size;
                offs_src = 0;
            }
            if (!size_dst) {
                blob_dst = *next_dst;
                next_dst = &blob_dst->next;
                size_dst = blob_dst->frag_size;
                offs_dst = 0;
            }
            auto now = std::min(size_src, size_dst);
            memcpy(blob_dst->data + offs_dst, blob_src->data + offs_src, now);
            s -= now;
            offs_src += now; size_src -= now;
            offs_dst += now; size_dst -= now;
        }
        assert(size_src == 0 && size_dst == 0);
    }

    managed_bytes(managed_bytes&& o) noexcept
        : _u(o._u)
    {
        if (external()) {
            if (_u.ptr) {
                _u.ptr->backref = &_u.ptr;
            }
        }
        o._u.small.size = 0;
    }

    managed_bytes& operator=(managed_bytes&& o) noexcept {
        if (this != &o) {
            this->~managed_bytes();
            new (this) managed_bytes(std::move(o));
        }
        return *this;
    }

    managed_bytes& operator=(const managed_bytes& o) {
        if (this != &o) {
            managed_bytes tmp(o);
            this->~managed_bytes();
            new (this) managed_bytes(std::move(tmp));
        }
        return *this;
    }

    bool operator==(const managed_bytes& o) const {
        if (size() != o.size()) {
            return false;
        }
        if (!external()) {
            return bytes_view(*this) == bytes_view(o);
        } else {
            auto a = _u.ptr;
            auto a_data = a->data;
            auto a_remain = a->frag_size;
            a = a->next;
            auto b = o._u.ptr;
            auto b_data = b->data;
            auto b_remain = b->frag_size;
            b = b->next;
            while (a_remain || b_remain) {
                auto now = std::min(a_remain, b_remain);
                if (bytes_view(a_data, now) != bytes_view(b_data, now)) {
                    return false;
                }
                a_data += now;
                a_remain -= now;
                if (!a_remain && a) {
                    a_data = a->data;
                    a_remain = a->frag_size;
                    a = a->next;
                }
                b_data += now;
                b_remain -= now;
                if (!b_remain && b) {
                    b_data = b->data;
                    b_remain = b->frag_size;
                    b = b->next;
                }
            }
            return true;
        }
    }

    bool operator!=(const managed_bytes& o) const {
        return !(*this == o);
    }

    operator bytes_view() const {
        return { data(), size() };
    }

    bool is_fragmented() const {
        return external() && _u.ptr->next;
    }

    operator bytes_mutable_view() {
        assert(!is_fragmented());
        return { data(), size() };
    };

    bytes_view::value_type& operator[](size_type index) {
        return value_at_index(index);
    }

    const bytes_view::value_type& operator[](size_type index) const {
        return const_cast<const bytes_view::value_type&>(
                const_cast<managed_bytes*>(this)->value_at_index(index));
    }

    size_type size() const {
        if (external()) {
            return _u.ptr->size;
        } else {
            return _u.small.size;
        }
    }

    const blob_storage::char_type* begin() const {
        return data();
    }

    const blob_storage::char_type* end() const {
        return data() + size();
    }

    blob_storage::char_type* begin() {
        return data();
    }

    blob_storage::char_type* end() {
        return data() + size();
    }

    bool empty() const {
        return _u.small.size == 0;
    }

    blob_storage::char_type* data() {
        if (external()) {
            assert(!_u.ptr->next);  // must be linearized
            return _u.ptr->data;
        } else {
            return _u.small.data;
        }
    }

    const blob_storage::char_type* data() const {
        return read_linearize();
    }

    // Returns the amount of external memory used.
    size_t external_memory_usage() const {
        if (external()) {
            size_t mem = 0;
            blob_storage* blob = _u.ptr;
            while (blob) {
                mem += blob->frag_size + sizeof(blob_storage);
                blob = blob->next;
            }
            return mem;
        }
        return 0;
    }

    template <typename Func>
    friend std::result_of_t<Func()> with_linearized_managed_bytes(Func&& func);
};

// Run func() while ensuring that reads of managed_bytes objects are
// temporarlily linearized
template <typename Func>
inline
std::result_of_t<Func()>
with_linearized_managed_bytes(Func&& func) {
    managed_bytes::linearization_context_guard g;
    return func();
}

namespace std {

template <>
struct hash<managed_bytes> {
    size_t operator()(const managed_bytes& v) const {
        return hash<bytes_view>()(v);
    }
};

}

// blob_storage is a variable-size type
inline
size_t
size_for_allocation_strategy(const blob_storage& bs) {
    return sizeof(bs) + bs.frag_size;
}
<commit_msg>managed_bytes: Mark read_linearize() as an allocation point<commit_after>
/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <stdint.h>
#include <memory>
#include "bytes.hh"
#include "utils/allocation_strategy.hh"
#include <seastar/core/unaligned.hh>
#include <seastar/util/alloc_failure_injector.hh>
#include <unordered_map>
#include <type_traits>

struct blob_storage {
    struct [[gnu::packed]] ref_type {
        blob_storage* ptr;

        ref_type() {}
        ref_type(blob_storage* ptr) : ptr(ptr) {}
        operator blob_storage*() const { return ptr; }
        blob_storage* operator->() const { return ptr; }
        blob_storage& operator*() const { return *ptr; }
    };
    using size_type = uint32_t;
    using char_type = bytes_view::value_type;

    ref_type* backref;
    size_type size;
    size_type frag_size;
    ref_type next;
    char_type data[];

    blob_storage(ref_type* backref, size_type size, size_type frag_size) noexcept
        : backref(backref)
        , size(size)
        , frag_size(frag_size)
        , next(nullptr)
    {
        *backref = this;
    }

    blob_storage(blob_storage&& o) noexcept
        : backref(o.backref)
        , size(o.size)
        , frag_size(o.frag_size)
        , next(o.next)
    {
        *backref = this;
        o.next = nullptr;
        if (next) {
            next->backref = &next;
        }
        memcpy(data, o.data, frag_size);
    }
} __attribute__((packed));

// A managed version of "bytes" (can be used with LSA).
class managed_bytes {
    static thread_local std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>> _lc_state;
    struct linearization_context {
        unsigned _nesting = 0;
        // Map from first blob_storage address to linearized version
        // We use the blob_storage address to be insentive to moving
        // a managed_bytes object.
        // linearization_context is entered often in the fast path, but it is
        // actually used only in rare (slow) cases.
        std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>>* _state_ptr = nullptr;
        void enter() {
            ++_nesting;
        }
        void leave() {
            if (!--_nesting && _state_ptr) {
                _state_ptr->clear();
                _state_ptr = nullptr;
            }
        }
        void forget(const blob_storage* p) noexcept;
    };
    static thread_local linearization_context _linearization_context;
public:
    struct linearization_context_guard {
        linearization_context_guard() {
            _linearization_context.enter();
        }
        ~linearization_context_guard() {
            _linearization_context.leave();
        }
    };
private:
    static constexpr size_t max_inline_size = 15;
    struct small_blob {
        bytes_view::value_type data[max_inline_size];
        int8_t size; // -1 -> use blob_storage
    };
    union u {
        u() {}
        ~u() {}
        blob_storage::ref_type ptr;
        small_blob small;
    } _u;
    static_assert(sizeof(small_blob) > sizeof(blob_storage*), "inline size too small");
private:
    bool external() const {
        return _u.small.size < 0;
    }
    size_t max_seg(allocation_strategy& alctr) {
        return alctr.preferred_max_contiguous_allocation() - sizeof(blob_storage);
    }
    void free_chain(blob_storage* p) noexcept {
        if (p->next && _linearization_context._nesting) {
            _linearization_context.forget(p);
        }
        auto& alctr = current_allocator();
        while (p) {
            auto n = p->next;
            alctr.destroy(p);
            p = n;
        }
    }
    const bytes_view::value_type* read_linearize() const {
        seastar::memory::on_alloc_point();
        if (!external()) {
            return _u.small.data;
        } else  if (!_u.ptr->next) {
            return _u.ptr->data;
        } else {
            return do_linearize();
        }
    }
    bytes_view::value_type& value_at_index(blob_storage::size_type index) {
        if (!external()) {
            return _u.small.data[index];
        }
        blob_storage* a = _u.ptr;
        while (index >= a->frag_size) {
            index -= a->frag_size;
            a = a->next;
        }
        return a->data[index];
    }
    const bytes_view::value_type* do_linearize() const;
public:
    using size_type = blob_storage::size_type;
    struct initialized_later {};

    managed_bytes() {
        _u.small.size = 0;
    }

    managed_bytes(const blob_storage::char_type* ptr, size_type size)
        : managed_bytes(bytes_view(ptr, size)) {}

    managed_bytes(const bytes& b) : managed_bytes(static_cast<bytes_view>(b)) {}

    managed_bytes(initialized_later, size_type size) {
        memory::on_alloc_point();
        if (size <= max_inline_size) {
            _u.small.size = size;
        } else {
            _u.small.size = -1;
            auto& alctr = current_allocator();
            auto maxseg = max_seg(alctr);
            auto now = std::min(size_t(size), maxseg);
            void* p = alctr.alloc(&get_standard_migrator<blob_storage>(),
                sizeof(blob_storage) + now, alignof(blob_storage));
            auto first = new (p) blob_storage(&_u.ptr, size, now);
            auto last = first;
            size -= now;
            try {
                while (size) {
                    auto now = std::min(size_t(size), maxseg);
                    void* p = alctr.alloc(&get_standard_migrator<blob_storage>(),
                        sizeof(blob_storage) + now, alignof(blob_storage));
                    last = new (p) blob_storage(&last->next, 0, now);
                    size -= now;
                }
            } catch (...) {
                free_chain(first);
                throw;
            }
        }
    }

    managed_bytes(bytes_view v) : managed_bytes(initialized_later(), v.size()) {
        if (!external()) {
            std::copy(v.begin(), v.end(), _u.small.data);
            return;
        }
        auto p = v.data();
        auto s = v.size();
        auto b = _u.ptr;
        while (s) {
            memcpy(b->data, p, b->frag_size);
            p += b->frag_size;
            s -= b->frag_size;
            b = b->next;
        }
        assert(!b);
    }

    managed_bytes(std::initializer_list<bytes::value_type> b) : managed_bytes(b.begin(), b.size()) {}

    ~managed_bytes() noexcept {
        if (external()) {
            free_chain(_u.ptr);
        }
    }

    managed_bytes(const managed_bytes& o) : managed_bytes(initialized_later(), o.size()) {
        if (!external()) {
            memcpy(data(), o.data(), size());
            return;
        }
        auto s = size();
        const blob_storage::ref_type* next_src = &o._u.ptr;
        blob_storage* blob_src = nullptr;
        size_type size_src = 0;
        size_type offs_src = 0;
        blob_storage::ref_type* next_dst = &_u.ptr;
        blob_storage* blob_dst = nullptr;
        size_type size_dst = 0;
        size_type offs_dst = 0;
        while (s) {
            if (!size_src) {
                blob_src = *next_src;
                next_src = &blob_src->next;
                size_src = blob_src->frag_size;
                offs_src = 0;
            }
            if (!size_dst) {
                blob_dst = *next_dst;
                next_dst = &blob_dst->next;
                size_dst = blob_dst->frag_size;
                offs_dst = 0;
            }
            auto now = std::min(size_src, size_dst);
            memcpy(blob_dst->data + offs_dst, blob_src->data + offs_src, now);
            s -= now;
            offs_src += now; size_src -= now;
            offs_dst += now; size_dst -= now;
        }
        assert(size_src == 0 && size_dst == 0);
    }

    managed_bytes(managed_bytes&& o) noexcept
        : _u(o._u)
    {
        if (external()) {
            if (_u.ptr) {
                _u.ptr->backref = &_u.ptr;
            }
        }
        o._u.small.size = 0;
    }

    managed_bytes& operator=(managed_bytes&& o) noexcept {
        if (this != &o) {
            this->~managed_bytes();
            new (this) managed_bytes(std::move(o));
        }
        return *this;
    }

    managed_bytes& operator=(const managed_bytes& o) {
        if (this != &o) {
            managed_bytes tmp(o);
            this->~managed_bytes();
            new (this) managed_bytes(std::move(tmp));
        }
        return *this;
    }

    bool operator==(const managed_bytes& o) const {
        if (size() != o.size()) {
            return false;
        }
        if (!external()) {
            return bytes_view(*this) == bytes_view(o);
        } else {
            auto a = _u.ptr;
            auto a_data = a->data;
            auto a_remain = a->frag_size;
            a = a->next;
            auto b = o._u.ptr;
            auto b_data = b->data;
            auto b_remain = b->frag_size;
            b = b->next;
            while (a_remain || b_remain) {
                auto now = std::min(a_remain, b_remain);
                if (bytes_view(a_data, now) != bytes_view(b_data, now)) {
                    return false;
                }
                a_data += now;
                a_remain -= now;
                if (!a_remain && a) {
                    a_data = a->data;
                    a_remain = a->frag_size;
                    a = a->next;
                }
                b_data += now;
                b_remain -= now;
                if (!b_remain && b) {
                    b_data = b->data;
                    b_remain = b->frag_size;
                    b = b->next;
                }
            }
            return true;
        }
    }

    bool operator!=(const managed_bytes& o) const {
        return !(*this == o);
    }

    operator bytes_view() const {
        return { data(), size() };
    }

    bool is_fragmented() const {
        return external() && _u.ptr->next;
    }

    operator bytes_mutable_view() {
        assert(!is_fragmented());
        return { data(), size() };
    };

    bytes_view::value_type& operator[](size_type index) {
        return value_at_index(index);
    }

    const bytes_view::value_type& operator[](size_type index) const {
        return const_cast<const bytes_view::value_type&>(
                const_cast<managed_bytes*>(this)->value_at_index(index));
    }

    size_type size() const {
        if (external()) {
            return _u.ptr->size;
        } else {
            return _u.small.size;
        }
    }

    const blob_storage::char_type* begin() const {
        return data();
    }

    const blob_storage::char_type* end() const {
        return data() + size();
    }

    blob_storage::char_type* begin() {
        return data();
    }

    blob_storage::char_type* end() {
        return data() + size();
    }

    bool empty() const {
        return _u.small.size == 0;
    }

    blob_storage::char_type* data() {
        if (external()) {
            assert(!_u.ptr->next);  // must be linearized
            return _u.ptr->data;
        } else {
            return _u.small.data;
        }
    }

    const blob_storage::char_type* data() const {
        return read_linearize();
    }

    // Returns the amount of external memory used.
    size_t external_memory_usage() const {
        if (external()) {
            size_t mem = 0;
            blob_storage* blob = _u.ptr;
            while (blob) {
                mem += blob->frag_size + sizeof(blob_storage);
                blob = blob->next;
            }
            return mem;
        }
        return 0;
    }

    template <typename Func>
    friend std::result_of_t<Func()> with_linearized_managed_bytes(Func&& func);
};

// Run func() while ensuring that reads of managed_bytes objects are
// temporarlily linearized
template <typename Func>
inline
std::result_of_t<Func()>
with_linearized_managed_bytes(Func&& func) {
    managed_bytes::linearization_context_guard g;
    return func();
}

namespace std {

template <>
struct hash<managed_bytes> {
    size_t operator()(const managed_bytes& v) const {
        return hash<bytes_view>()(v);
    }
};

}

// blob_storage is a variable-size type
inline
size_t
size_for_allocation_strategy(const blob_storage& bs) {
    return sizeof(bs) + bs.frag_size;
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

x
  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.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) :
    d_ptr(new MimeMessagePrivate)
{
    Q_D(MimeMessage);
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::~MimeMessage()
{
    delete d_ptr;
}

MimePart& MimeMessage::getContent()
{
    Q_D(MimeMessage);
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    Q_D(MimeMessage);
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device)
{
    Q_D(const MimeMessage);

    // Headers
    QByteArray data;

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        return false;
    }

    return true;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    Q_D(MimeMessage);
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    Q_D(MimeMessage);
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    Q_D(MimeMessage);
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    Q_D(MimeMessage);
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString & subject)
{
    Q_D(MimeMessage);
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    Q_D(MimeMessage);
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ((MimeMultiPart*) d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    Q_D(MimeMessage);
    d->encoding = hEnc;
}

EmailAddress MimeMessage::sender() const
{
    Q_D(const MimeMessage);
    return d->sender;
}

QString MimeMessage::subject() const
{
    Q_D(const MimeMessage);
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    Q_D(const MimeMessage);

    QList<MimePart*> ret;
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << ((double) printable/sum) << (encoded/sum);
        if (sum != 0 && ((double) printable/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<commit_msg>Add Date: header field as required by RFC5322<commit_after>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

x
  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.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QDateTime>
#include <QLocale>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) :
    d_ptr(new MimeMessagePrivate)
{
    Q_D(MimeMessage);
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::~MimeMessage()
{
    delete d_ptr;
}

MimePart& MimeMessage::getContent()
{
    Q_D(MimeMessage);
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    Q_D(MimeMessage);
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device)
{
    Q_D(const MimeMessage);

    // Headers
    QByteArray data;

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    const auto dt = QDateTime::currentDateTime();
    data = QByteArrayLiteral("Date: ") + QLocale::c().toString(dt, QStringLiteral("ddd, d MMM yyyy HH:mm:ss ")).toLatin1();
    int utcOffset = dt.offsetFromUtc();
    if (utcOffset == 0) {
        data.append(QByteArrayLiteral("+0000"));
    } else {
        const bool negative = (utcOffset < 0);
        if (negative) {
            data.append('-');
            utcOffset *= -1;
        } else {
            data.append('+');
        }
        const auto offsetTime = QTime::fromMSecsSinceStartOfDay(utcOffset * 1000);
        data.append(offsetTime.toString(QStringLiteral("HHmm")).toLatin1());
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        return false;
    }

    return true;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    Q_D(MimeMessage);
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    Q_D(MimeMessage);
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    Q_D(MimeMessage);
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    Q_D(MimeMessage);
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString & subject)
{
    Q_D(MimeMessage);
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    Q_D(MimeMessage);
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ((MimeMultiPart*) d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    Q_D(MimeMessage);
    d->encoding = hEnc;
}

EmailAddress MimeMessage::sender() const
{
    Q_D(const MimeMessage);
    return d->sender;
}

QString MimeMessage::subject() const
{
    Q_D(const MimeMessage);
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    Q_D(const MimeMessage);

    QList<MimePart*> ret;
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << ((double) printable/sum) << (encoded/sum);
        if (sum != 0 && ((double) printable/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<|endoftext|>


<commit_before>#include "uploadersingleton.hpp"
#include "customuploader.hpp"
#include "default/clipboarduploader.hpp"
#include "default/imguruploader.hpp"
#include <QDebug>
#include <QDir>
#include <QStandardPaths>
#include <formatter.hpp>
#include <settings.hpp>

UploaderSingleton::UploaderSingleton()
: QObject(), saveDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) {
    if (QStandardPaths::writableLocation(QStandardPaths::PicturesLocation).isEmpty()) {
        qFatal("Cannot determine location for pictures");
    }
    if (!saveDir.exists()) {
        if (!saveDir.mkpath(".")) {
            qFatal("Could not create the path %s to store images in!", saveDir.absoluteFilePath(".").toLocal8Bit().constData());
        }
    }
    QDir configDir(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
    configDir.mkpath("KShare/uploaders");
    configDir.cd("KShare/uploaders");
    configDir.setNameFilters({ "*.uploader" });
    for (QString file : configDir.entryList()) {
        try {
            registerUploader(new CustomUploader(configDir.absoluteFilePath(file)));
        } catch (std::runtime_error e) {
            qWarning() << e.what();
            errs << e;
        }
    }

    // UPLOADERS
    registerUploader(new ImgurUploader);
    registerUploader(new ClipboardUploader);
    // ---------

    if (settings::settings().contains("uploader"))
        uploader = settings::settings().value("uploader").toString();
    else
        settings::settings().setValue("uploader", uploader);
    if (!uploaders.contains(uploader)) {
        settings::settings().setValue("uploader", uploader);
        uploader = "imgur";
    }
}

void UploaderSingleton::registerUploader(Uploader *uploader) {
    if (uploaders.contains(uploader->name())) {
        throw std::runtime_error(("Ambigious uploader " + uploader->name()).toStdString());
    }
    uploaders.insert(uploader->name(), uploader);
    emit newUploader(uploader);
}

void UploaderSingleton::upload(QPixmap *pixmap) {
    if (settings::settings().contains("fileFormat")) {
        QString format = settings::settings().value("fileFormat").toString();
        if (!format.isEmpty()) {
            pixmap->save(saveDir.absoluteFilePath(formatter::format(format) + ".png"), "PNG");
        }
    }
    uploaders.value(uploader)->doUpload(pixmap);
    delete pixmap;
}

QList<Uploader *> UploaderSingleton::uploaderList() {
    return uploaders.values();
}

void UploaderSingleton::set(QString uploader) {
    if (uploaders.contains(uploader)) {
        this->uploader = uploader;
        settings::settings().setValue("uploader", uploader);
    }
}

QString UploaderSingleton::selectedUploader() {
    return uploader;
}

QList<std::runtime_error> UploaderSingleton::errors() {
    return errs;
}
<commit_msg>Why was this the other thing<commit_after>#include "uploadersingleton.hpp"
#include "customuploader.hpp"
#include "default/clipboarduploader.hpp"
#include "default/imguruploader.hpp"
#include <QDebug>
#include <QDir>
#include <QStandardPaths>
#include <formatter.hpp>
#include <settings.hpp>

UploaderSingleton::UploaderSingleton()
: QObject(), saveDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) {
    if (QStandardPaths::writableLocation(QStandardPaths::PicturesLocation).isEmpty()) {
        qFatal("Cannot determine location for pictures");
    }
    if (!saveDir.exists()) {
        if (!saveDir.mkpath(".")) {
            qFatal("Could not create the path %s to store images in!", saveDir.absolutePath().toLocal8Bit().constData());
        }
    }
    QDir configDir(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
    configDir.mkpath("KShare/uploaders");
    configDir.cd("KShare/uploaders");
    configDir.setNameFilters({ "*.uploader" });
    for (QString file : configDir.entryList()) {
        try {
            registerUploader(new CustomUploader(configDir.absoluteFilePath(file)));
        } catch (std::runtime_error e) {
            qWarning() << e.what();
            errs << e;
        }
    }

    // UPLOADERS
    registerUploader(new ImgurUploader);
    registerUploader(new ClipboardUploader);
    // ---------

    if (settings::settings().contains("uploader"))
        uploader = settings::settings().value("uploader").toString();
    else
        settings::settings().setValue("uploader", uploader);
    if (!uploaders.contains(uploader)) {
        settings::settings().setValue("uploader", uploader);
        uploader = "imgur";
    }
}

void UploaderSingleton::registerUploader(Uploader *uploader) {
    if (uploaders.contains(uploader->name())) {
        throw std::runtime_error(("Ambigious uploader " + uploader->name()).toStdString());
    }
    uploaders.insert(uploader->name(), uploader);
    emit newUploader(uploader);
}

void UploaderSingleton::upload(QPixmap *pixmap) {
    if (settings::settings().contains("fileFormat")) {
        QString format = settings::settings().value("fileFormat").toString();
        if (!format.isEmpty()) {
            pixmap->save(saveDir.absoluteFilePath(formatter::format(format) + ".png"), "PNG");
        }
    }
    uploaders.value(uploader)->doUpload(pixmap);
    delete pixmap;
}

QList<Uploader *> UploaderSingleton::uploaderList() {
    return uploaders.values();
}

void UploaderSingleton::set(QString uploader) {
    if (uploaders.contains(uploader)) {
        this->uploader = uploader;
        settings::settings().setValue("uploader", uploader);
    }
}

QString UploaderSingleton::selectedUploader() {
    return uploader;
}

QList<std::runtime_error> UploaderSingleton::errors() {
    return errs;
}
<|endoftext|>


<commit_before>/*
 * SEGS - Super Entity Game Server
 * http://www.segs.io/
 * Copyright (c) 2006 - 2019 SEGS Team (see AUTHORS.md)
 * This software is licensed under the terms of the 3-clause BSD License. See LICENSE.md for details.
 */

/*!
 * @addtogroup GameData Projects/CoX/Common/GameData
 * @{
 */

#include "Movement.h"

#include "Entity.h"
#include "Character.h"
#include "CharacterHelpers.h"
#include "Servers/MapServer/DataHelpers.h"
#include "Common/GameData/CoHMath.h"
#include "Common/GameData/seq_definitions.h"
#include "Common/GameData/playerdata_definitions.h"
#include "Logging.h"

#include <glm/gtx/vector_query.hpp>
#include <glm/ext.hpp>
#include <chrono>

static const glm::mat3  s_identity_matrix = glm::mat3(1.0f);
static int          s_landed_on_ground = 0;
//static CollInfo     s_last_surf;
static const int s_reverse_control_dir[6] = {
    BinaryControl::BACKWARD,
    BinaryControl::FORWARD,
    BinaryControl::RIGHT,
    BinaryControl::LEFT,
    BinaryControl::DOWN,
    BinaryControl::UP,
};

SurfaceParams g_world_surf_params[2] = {
    // traction, friction, bounce, gravity, max_speed
    //{ 1.00f, 0.45f, 0.01f, 0.065f, 1.00f },    // ground; from client (base to be modified later)
    //{ 0.02f, 0.01f, 0.00f, 0.065f, 1.00f },    // air; from client (base to be modified later)
    { 1.00f, 1.00f, 0.01f, 3.00f, 1.00f },    // ground; test values
    { 1.00f, 3.00f, 0.00f, 3.00f, 2.00f },    // air; test values
};

void roundVelocityToZero(glm::vec3 *vel)
{
    if(std::abs(vel->x) < 0.00001f)
        vel->x = 0;
    if(std::abs(vel->y) < 0.00001f)
        vel->y = 0;
    if(std::abs(vel->z) < 0.00001f)
        vel->z = 0;
}

void processDirectionControl(InputState *next_state, uint8_t control_id, int ms_since_prev, int keypress_state)
{
    float delta = 0.0f;

    if(keypress_state)
        delta = 1.0f;

    qCDebug(logInput, "Pressed dir: %s \t ms_since_prev: %d \t press_release: %d", control_name[control_id], ms_since_prev, keypress_state);
    switch(control_id)
    {
        case 0: next_state->m_pos_delta[2] = delta; break;    // FORWARD
        case 1: next_state->m_pos_delta[2] = -delta; break;   // BACKWARD
        case 2: next_state->m_pos_delta[0] = -delta; break;   // LEFT
        case 3: next_state->m_pos_delta[0] = delta; break;    // RIGHT
        case 4: next_state->m_pos_delta[1] = delta; break;    // UP
        case 5: next_state->m_pos_delta[1] = -delta; break;   // DOWN
    }

    switch(control_id)
    {
        case 0:
        case 1: next_state->m_pos_delta_valid[2] = true; break;
        case 2:
        case 3: next_state->m_pos_delta_valid[0] = true; break;
        case 4:
        case 5: next_state->m_pos_delta_valid[1] = true; break;
    }
}

void setVelocity(Entity &e) // pmotionSetVel
{
    InputState  *state  = &e.m_states.m_inp_states.back();
    MotionState *motion = &e.m_motion_state;
    glm::vec3   horiz_vel       = {0, 0, 0};
    glm::vec3   vel             = {0, 0, 0};

    float       control_amounts[6] = {0};
    int         max_press_time  = 0;
    float       vel_scale_copy  = state->m_velocity_scale;

    if(state->m_no_collision)
        e.m_move_type |= MoveType::MOVETYPE_NOCOLL;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_NOCOLL;

    if(state->m_no_collision
            && e.m_player->m_options.alwaysmobile
            && (motion->m_controls_disabled || state->m_landing_recovery_time || state->m_controls_disabled))
    {
        if(e.m_type == EntType::PLAYER)
            qCDebug(logMovement) << "Input Vel is <0, 0, 0>. No coll?" << state->m_no_collision;

        motion->m_input_velocity = vel;
    }
    else
    {
        for (int i = BinaryControl::FORWARD; i < BinaryControl::LAST_BINARY_VALUE; ++i)
        {
            float press_time = state->m_keypress_time[i];

            if(press_time > 0)
                qCDebug(logMovement) << "keypress_time" << i << press_time;

            if(press_time > max_press_time)
                max_press_time = state->m_keypress_time[i];

            if(i >= BinaryControl::UP && !motion->m_is_flying) // UP or Fly
                control_amounts[i] = (float)(press_time != 0);
            else if(!press_time)
                control_amounts[i] = 0.0f;
            else if(press_time >= 1000)
                control_amounts[i] = 1.0f;
            else if(press_time <= 50 && state->m_control_bits[i])
                control_amounts[i] = 0.0f;
            else if(press_time >= 75)
            {
                if(press_time < 75 || press_time >= 100)
                    control_amounts[i] = (press_time - 100) * 0.004f / 9.0f + 0.6f;
                else
                    control_amounts[i] = std::pow((press_time - 75) * 0.04f, 2.0f) * 0.4f + 0.2f;
            }
            else
                control_amounts[i] = 0.2f;

            if(control_amounts[i] > 0.0f)
                qCDebug(logMovement) << "control_amounts:" << i << control_amounts[i];
        }

        state->m_move_time = max_press_time;
        vel.x = control_amounts[BinaryControl::RIGHT] - control_amounts[BinaryControl::LEFT];
        vel.y = control_amounts[BinaryControl::UP] - control_amounts[BinaryControl::DOWN];
        vel.z = control_amounts[BinaryControl::FORWARD] - control_amounts[BinaryControl::BACKWARD];
        vel.x = vel.x * motion->m_speed.x;
        vel.y = vel.y * motion->m_speed.y;
        horiz_vel = vel;

        if(e.m_type == EntType::PLAYER && glm::length(vel))
            qCDebug(logMovement) << "vel:" << glm::to_string(vel).c_str();

        if(!motion->m_is_flying)
            horiz_vel.y = 0.0f;

        if(vel.z < 0.0f)
            vel_scale_copy *= motion->m_backup_spd;

        if(motion->m_is_stunned)
            vel_scale_copy *= 0.1f;

        // Client returns 0 for negative length vector
        if(glm::length(horiz_vel) <= 0.0f)
            horiz_vel = glm::vec3(0,0,0);
        else
            horiz_vel = glm::normalize(horiz_vel);

        if(e.m_type == EntType::PLAYER && glm::length(horiz_vel))
            qCDebug(logMovement) << "horizVel:" << glm::to_string(horiz_vel).c_str();

        if(state->m_speed_scale != 0.0f)
            vel_scale_copy *= state->m_speed_scale;

        motion->m_velocity_scale = vel_scale_copy;
        vel.x = horiz_vel.x * std::fabs(control_amounts[BinaryControl::RIGHT] - control_amounts[BinaryControl::LEFT]);
        vel.z = horiz_vel.z * std::fabs(control_amounts[BinaryControl::FORWARD] - control_amounts[BinaryControl::BACKWARD]);

        if(motion->m_is_flying)
            vel.y = horiz_vel.y * std::fabs(control_amounts[BinaryControl::UP] - control_amounts[BinaryControl::DOWN]);
        else if(e.m_states.previous()->m_control_bits[BinaryControl::UP] && !state->m_control_bits[BinaryControl::UP])
            vel.y = 0.0f;
        else
        {
            vel.y *= glm::clamp(motion->m_jump_height, 0.0f, 1.0f);
            if(!e.m_motion_state.m_is_sliding)
                e.m_motion_state.m_flag_5 = false; // flag_5 moving on y-axis?
        }
     }

    // Movement Flags
    if(motion->m_is_flying)
        e.m_move_type |= MoveType::MOVETYPE_FLY;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_FLY;

    if(motion->m_has_jumppack)
        e.m_move_type |= MoveType::MOVETYPE_JETPACK;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_JETPACK;

    motion->m_input_velocity = vel;

    if(e.m_type == EntType::PLAYER && glm::length(vel))
        qCDebug(logMovement) << "final vel:" << glm::to_string(vel).c_str();

    if(e.m_char->m_char_data.m_afk && motion->m_input_velocity != glm::vec3(0,0,0))
    {
        if(e.m_type == EntType::PLAYER)
            qCDebug(logMovement) << "Moving so turning off AFK";

        toggleAFK(*e.m_char);
    }

    // setPlayerVelQuat(&vel, vel_scale_copy); // we don't need this?
    motion->m_velocity = vel;
}

void addPosUpdate(Entity &e, const PosUpdate &p)
{
    e.m_update_idx = (e.m_update_idx+1) % 64;
    e.m_pos_updates[e.m_update_idx] = p;
}

bool updateRotation(const Entity &src, int axis ) /* returns true if given axis needs updating */
{
    if(src.m_states.previous() == nullptr)
        return true;

    if(src.m_states.previous()->m_orientation_pyr[axis] == src.m_states.current()->m_orientation_pyr[axis])
        return false;

    return true;
}

void forcePosition(Entity &e, glm::vec3 pos)
{
    e.m_entity_data.m_pos = pos;
    e.m_force_pos_and_cam = true;
}

void forceOrientation(Entity &e, glm::vec3 pyr)
{
    e.m_direction = glm::quat(pyr);
    e.m_entity_data.m_orientation_pyr = pyr;
    e.m_force_pos_and_cam = true;
}

// Move to Sequences or Triggers files later
void addTriggeredMove(Entity &e, uint32_t move_idx, uint32_t delay, uint32_t fx_idx)
{
    e.m_update_anims = true;
    e.m_rare_update = true;

    TriggeredMove tmove;
    tmove.m_move_idx = move_idx;
    tmove.m_ticks_to_delay = delay;
    tmove.m_trigger_fx_idx = fx_idx;

    e.m_triggered_moves.push_back(tmove);
    qCDebug(logAnimations) << "Queueing triggered move:"
                           << move_idx << delay << fx_idx;
}

//! @}
<commit_msg>Adjusted surface params (#823)<commit_after>/*
 * SEGS - Super Entity Game Server
 * http://www.segs.io/
 * Copyright (c) 2006 - 2019 SEGS Team (see AUTHORS.md)
 * This software is licensed under the terms of the 3-clause BSD License. See LICENSE.md for details.
 */

/*!
 * @addtogroup GameData Projects/CoX/Common/GameData
 * @{
 */

#include "Movement.h"

#include "Entity.h"
#include "Character.h"
#include "CharacterHelpers.h"
#include "Servers/MapServer/DataHelpers.h"
#include "Common/GameData/CoHMath.h"
#include "Common/GameData/seq_definitions.h"
#include "Common/GameData/playerdata_definitions.h"
#include "Logging.h"

#include <glm/gtx/vector_query.hpp>
#include <glm/ext.hpp>
#include <chrono>

static const glm::mat3  s_identity_matrix = glm::mat3(1.0f);
static int          s_landed_on_ground = 0;
//static CollInfo     s_last_surf;
static const int s_reverse_control_dir[6] = {
    BinaryControl::BACKWARD,
    BinaryControl::FORWARD,
    BinaryControl::RIGHT,
    BinaryControl::LEFT,
    BinaryControl::DOWN,
    BinaryControl::UP,
};

SurfaceParams g_world_surf_params[2] = {
    // traction, friction, bounce, gravity, max_speed
    //{ 1.00f, 0.45f, 0.01f, 0.065f, 1.00f }, // ground; from client (base to be modified later)
    //{ 0.02f, 0.01f, 0.00f, 0.065f, 1.00f },  // air; from client (base to be modified later)
    { 1.30f, 1.00f, 0.01f, 3.00f, 1.70f },      // ground; test values
    { 1.50f, 3.00f, 0.00f, 3.00f, 3.00f },      // air; test values
};

void roundVelocityToZero(glm::vec3 *vel)
{
    if(std::abs(vel->x) < 0.00001f)
        vel->x = 0;
    if(std::abs(vel->y) < 0.00001f)
        vel->y = 0;
    if(std::abs(vel->z) < 0.00001f)
        vel->z = 0;
}

void processDirectionControl(InputState *next_state, uint8_t control_id, int ms_since_prev, int keypress_state)
{
    float delta = 0.0f;

    if(keypress_state)
        delta = 1.0f;

    qCDebug(logInput, "Pressed dir: %s \t ms_since_prev: %d \t press_release: %d", control_name[control_id], ms_since_prev, keypress_state);
    switch(control_id)
    {
        case 0: next_state->m_pos_delta[2] = delta; break;    // FORWARD
        case 1: next_state->m_pos_delta[2] = -delta; break;   // BACKWARD
        case 2: next_state->m_pos_delta[0] = -delta; break;   // LEFT
        case 3: next_state->m_pos_delta[0] = delta; break;    // RIGHT
        case 4: next_state->m_pos_delta[1] = delta; break;    // UP
        case 5: next_state->m_pos_delta[1] = -delta; break;   // DOWN
    }

    switch(control_id)
    {
        case 0:
        case 1: next_state->m_pos_delta_valid[2] = true; break;
        case 2:
        case 3: next_state->m_pos_delta_valid[0] = true; break;
        case 4:
        case 5: next_state->m_pos_delta_valid[1] = true; break;
    }
}

void setVelocity(Entity &e) // pmotionSetVel
{
    InputState  *state  = &e.m_states.m_inp_states.back();
    MotionState *motion = &e.m_motion_state;
    glm::vec3   horiz_vel       = {0, 0, 0};
    glm::vec3   vel             = {0, 0, 0};

    float       control_amounts[6] = {0};
    int         max_press_time  = 0;
    float       vel_scale_copy  = state->m_velocity_scale;

    if(state->m_no_collision)
        e.m_move_type |= MoveType::MOVETYPE_NOCOLL;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_NOCOLL;

    if(state->m_no_collision
            && e.m_player->m_options.alwaysmobile
            && (motion->m_controls_disabled || state->m_landing_recovery_time || state->m_controls_disabled))
    {
        if(e.m_type == EntType::PLAYER)
            qCDebug(logMovement) << "Input Vel is <0, 0, 0>. No coll?" << state->m_no_collision;

        motion->m_input_velocity = vel;
    }
    else
    {
        for (int i = BinaryControl::FORWARD; i < BinaryControl::LAST_BINARY_VALUE; ++i)
        {
            float press_time = state->m_keypress_time[i];

            if(press_time > 0)
                qCDebug(logMovement) << "keypress_time" << i << press_time;

            if(press_time > max_press_time)
                max_press_time = state->m_keypress_time[i];

            if(i >= BinaryControl::UP && !motion->m_is_flying) // UP or Fly
                control_amounts[i] = (float)(press_time != 0);
            else if(!press_time)
                control_amounts[i] = 0.0f;
            else if(press_time >= 1000)
                control_amounts[i] = 1.0f;
            else if(press_time <= 50 && state->m_control_bits[i])
                control_amounts[i] = 0.0f;
            else if(press_time >= 75)
            {
                if(press_time < 75 || press_time >= 100)
                    control_amounts[i] = (press_time - 100) * 0.004f / 9.0f + 0.6f;
                else
                    control_amounts[i] = std::pow((press_time - 75) * 0.04f, 2.0f) * 0.4f + 0.2f;
            }
            else
                control_amounts[i] = 0.2f;

            if(control_amounts[i] > 0.0f)
                qCDebug(logMovement) << "control_amounts:" << i << control_amounts[i];
        }

        state->m_move_time = max_press_time;
        vel.x = control_amounts[BinaryControl::RIGHT] - control_amounts[BinaryControl::LEFT];
        vel.y = control_amounts[BinaryControl::UP] - control_amounts[BinaryControl::DOWN];
        vel.z = control_amounts[BinaryControl::FORWARD] - control_amounts[BinaryControl::BACKWARD];
        vel.x = vel.x * motion->m_speed.x;
        vel.y = vel.y * motion->m_speed.y;
        horiz_vel = vel;

        if(e.m_type == EntType::PLAYER && glm::length(vel))
            qCDebug(logMovement) << "vel:" << glm::to_string(vel).c_str();

        if(!motion->m_is_flying)
            horiz_vel.y = 0.0f;

        if(vel.z < 0.0f)
            vel_scale_copy *= motion->m_backup_spd;

        if(motion->m_is_stunned)
            vel_scale_copy *= 0.1f;

        // Client returns 0 for negative length vector
        if(glm::length(horiz_vel) <= 0.0f)
            horiz_vel = glm::vec3(0,0,0);
        else
            horiz_vel = glm::normalize(horiz_vel);

        if(e.m_type == EntType::PLAYER && glm::length(horiz_vel))
            qCDebug(logMovement) << "horizVel:" << glm::to_string(horiz_vel).c_str();

        if(state->m_speed_scale != 0.0f)
            vel_scale_copy *= state->m_speed_scale;

        motion->m_velocity_scale = vel_scale_copy;
        vel.x = horiz_vel.x * std::fabs(control_amounts[BinaryControl::RIGHT] - control_amounts[BinaryControl::LEFT]);
        vel.z = horiz_vel.z * std::fabs(control_amounts[BinaryControl::FORWARD] - control_amounts[BinaryControl::BACKWARD]);

        if(motion->m_is_flying)
            vel.y = horiz_vel.y * std::fabs(control_amounts[BinaryControl::UP] - control_amounts[BinaryControl::DOWN]);
        else if(e.m_states.previous()->m_control_bits[BinaryControl::UP] && !state->m_control_bits[BinaryControl::UP])
            vel.y = 0.0f;
        else
        {
            vel.y *= glm::clamp(motion->m_jump_height, 0.0f, 1.0f);
            if(!e.m_motion_state.m_is_sliding)
                e.m_motion_state.m_flag_5 = false; // flag_5 moving on y-axis?
        }
     }

    // Movement Flags
    if(motion->m_is_flying)
        e.m_move_type |= MoveType::MOVETYPE_FLY;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_FLY;

    if(motion->m_has_jumppack)
        e.m_move_type |= MoveType::MOVETYPE_JETPACK;
    else
        e.m_move_type &= ~MoveType::MOVETYPE_JETPACK;

    motion->m_input_velocity = vel;

    if(e.m_type == EntType::PLAYER && glm::length(vel))
        qCDebug(logMovement) << "final vel:" << glm::to_string(vel).c_str();

    if(e.m_char->m_char_data.m_afk && motion->m_input_velocity != glm::vec3(0,0,0))
    {
        if(e.m_type == EntType::PLAYER)
            qCDebug(logMovement) << "Moving so turning off AFK";

        toggleAFK(*e.m_char);
    }

    // setPlayerVelQuat(&vel, vel_scale_copy); // we don't need this?
    motion->m_velocity = vel;
}

void addPosUpdate(Entity &e, const PosUpdate &p)
{
    e.m_update_idx = (e.m_update_idx+1) % 64;
    e.m_pos_updates[e.m_update_idx] = p;
}

bool updateRotation(const Entity &src, int axis ) /* returns true if given axis needs updating */
{
    if(src.m_states.previous() == nullptr)
        return true;

    if(src.m_states.previous()->m_orientation_pyr[axis] == src.m_states.current()->m_orientation_pyr[axis])
        return false;

    return true;
}

void forcePosition(Entity &e, glm::vec3 pos)
{
    e.m_entity_data.m_pos = pos;
    e.m_force_pos_and_cam = true;
}

void forceOrientation(Entity &e, glm::vec3 pyr)
{
    e.m_direction = glm::quat(pyr);
    e.m_entity_data.m_orientation_pyr = pyr;
    e.m_force_pos_and_cam = true;
}

// Move to Sequences or Triggers files later
void addTriggeredMove(Entity &e, uint32_t move_idx, uint32_t delay, uint32_t fx_idx)
{
    e.m_update_anims = true;
    e.m_rare_update = true;

    TriggeredMove tmove;
    tmove.m_move_idx = move_idx;
    tmove.m_ticks_to_delay = delay;
    tmove.m_trigger_fx_idx = fx_idx;

    e.m_triggered_moves.push_back(tmove);
    qCDebug(logAnimations) << "Queueing triggered move:"
                           << move_idx << delay << fx_idx;
}

//! @}
<|endoftext|>


<commit_before>#include <string>

#include <sqlite3.h>

#include "cell.h"
#include "rtl_exec.h"

static int callback(void *rowscell, int columns, char **values, char ** /*names*/)
{
    std::vector<Cell> *rows = static_cast<std::vector<Cell> *>(rowscell);
    std::vector<Cell> row;
    for (int i = 0; i < columns; i++) {
        row.push_back(Cell(values[i]));
    }
    rows->push_back(Cell(row));
    return 0;
}

namespace rtl {

namespace sqlite {

void *open(const std::string &name)
{
    sqlite3 *db;
    int r = sqlite3_open(name.c_str(), &db);
    if (r != SQLITE_OK) {
    }
    return db;
}

Cell exec(void *db, const std::string &sql, const std::map<utf8string, utf8string> &parameters)
{
    std::vector<Cell> rows;
    sqlite3_stmt *stmt;
    int r = sqlite3_prepare_v2(static_cast<sqlite3 *>(db), sql.c_str(), -1, &stmt, NULL);
    if (r != SQLITE_OK) {
        fprintf(stderr, "sqlite3_prepare error %d ext=%d\n", r, sqlite3_extended_errcode(static_cast<sqlite3 *>(db)));
    }
    for (auto p: parameters) {
        int c = sqlite3_bind_parameter_index(stmt, p.first.c_str());
        if (c == 0) {
            throw RtlException(Exception_ParameterNameException, p.first.c_str());
        }
        r = sqlite3_bind_text(stmt, c, p.second.c_str(), -1, SQLITE_TRANSIENT);
        if (r != SQLITE_OK) {
            fprintf(stderr, "sqlite3_bind_text error\n");
        }
    }
    int columns = sqlite3_column_count(stmt);
    for (;;) {
        r = sqlite3_step(stmt);
        if (r == SQLITE_DONE) {
            break;
        }
        if (r == SQLITE_ROW) {
            std::vector<Cell> row;
            for (int i = 0; i < columns; i++) {
                row.push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
            }
            rows.push_back(Cell(row));
        } else {
            fprintf(stderr, "sqlite3_step error\n");
            break;
        }
    }
    sqlite3_finalize(stmt);
    return Cell(rows);
}

bool execOne(void *db, const std::string &sql, const std::map<utf8string, utf8string> &parameters, Cell *result)
{
    sqlite3_stmt *stmt;
    int r = sqlite3_prepare_v2(static_cast<sqlite3 *>(db), sql.c_str(), -1, &stmt, NULL);
    if (r != SQLITE_OK) {
        fprintf(stderr, "sqlite3_prepare error %d ext=%d\n", r, sqlite3_extended_errcode(static_cast<sqlite3 *>(db)));
    }
    for (auto p: parameters) {
        int c = sqlite3_bind_parameter_index(stmt, p.first.c_str());
        if (c == 0) {
            throw RtlException(Exception_ParameterNameException, p.first.c_str());
        }
        r = sqlite3_bind_text(stmt, c, p.second.c_str(), -1, SQLITE_TRANSIENT);
        if (r != SQLITE_OK) {
            fprintf(stderr, "sqlite3_bind_text error\n");
        }
    }
    int columns = sqlite3_column_count(stmt);
    r = sqlite3_step(stmt);
    if (r == SQLITE_DONE) {
        //fprintf(stderr, "sqlite no data: %s\n", sql.c_str());
        return false;
    }
    if (r == SQLITE_ROW) {
        for (int i = 0; i < columns; i++) {
            result->array_for_write().push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
        }
    } else {
        //fprintf(stderr, "sqlite3_step error: %s\n", sql.c_str());
        return false;
    }
    sqlite3_finalize(stmt);
    return true;
}

Cell execRaw(void *db, const std::string &sql)
{
    std::vector<Cell> rows;
    char *errmsg;
    int r = sqlite3_exec(static_cast<sqlite3 *>(db), sql.c_str(), callback, &rows, &errmsg);
    if (r != SQLITE_OK) {
        fprintf(stderr, "sqlite3_exec error: %s\n", errmsg);
    }
    return Cell(rows);
}

void close(void *db)
{
    sqlite3_close(static_cast<sqlite3 *>(db));
}

class Cursor {
public:
    Cursor(sqlite3 *db, const std::string &query): db(db), query(query), stmt(nullptr), columns(0) {}
    virtual ~Cursor() {}
    void open()
    {
        int r = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
        if (r != SQLITE_OK) {
            fprintf(stderr, "sqlite3_prepare error %d ext=%d\n", r, sqlite3_extended_errcode(db));
        }
        columns = sqlite3_column_count(stmt);
    }
    bool fetch(Cell *result)
    {
        int r = sqlite3_step(stmt);
        if (r == SQLITE_DONE) {
            //fprintf(stderr, "sqlite no data: %s\n", sql.c_str());
            return false;
        }
        if (r == SQLITE_ROW) {
            for (int i = 0; i < columns; i++) {
                result->array_for_write().push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
            }
        } else {
            //fprintf(stderr, "sqlite3_step error: %s\n", sql.c_str());
            return false;
        }
        return true;
    }
    void close()
    {
        sqlite3_finalize(stmt);
    }

    sqlite3 *db;
    const std::string query;
    sqlite3_stmt *stmt;
    int columns;
private:
    Cursor(const Cursor &);
    Cursor &operator=(const Cursor &);
};

std::map<std::string, std::unique_ptr<Cursor>> Cursors;

std::string cursorDeclare(void *db, const std::string &name, const std::string &query)
{
    Cursors[name] = std::unique_ptr<Cursor> { new Cursor(static_cast<sqlite3 *>(db), query) };
    return name;
}

void cursorOpen(const std::string &name)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    c->second->open();
}

bool cursorFetch(const std::string &name, Cell *result)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    return c->second->fetch(result);
}

void cursorClose(const std::string &name)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    c->second->close();
    Cursors.erase(c);
}

} // namespace sqlite

} // namespace rtl
<commit_msg>Add actual error handling in sqlite<commit_after>#include <string>

#include <sqlite3.h>

#include "cell.h"
#include "rtl_exec.h"

static int callback(void *rowscell, int columns, char **values, char ** /*names*/)
{
    std::vector<Cell> *rows = static_cast<std::vector<Cell> *>(rowscell);
    std::vector<Cell> row;
    for (int i = 0; i < columns; i++) {
        row.push_back(Cell(values[i]));
    }
    rows->push_back(Cell(row));
    return 0;
}

namespace rtl {

namespace sqlite {

void *open(const std::string &name)
{
    sqlite3 *db;
    int r = sqlite3_open(name.c_str(), &db);
    if (r != SQLITE_OK) {
        throw RtlException(global::Exception_SqlException, sqlite3_errmsg(db), r);
    }
    return db;
}

Cell exec(void *db, const std::string &sql, const std::map<utf8string, utf8string> &parameters)
{
    std::vector<Cell> rows;
    sqlite3_stmt *stmt;
    int r = sqlite3_prepare_v2(static_cast<sqlite3 *>(db), sql.c_str(), -1, &stmt, NULL);
    if (r != SQLITE_OK) {
        throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
    }
    for (auto p: parameters) {
        int c = sqlite3_bind_parameter_index(stmt, p.first.c_str());
        if (c == 0) {
            throw RtlException(Exception_ParameterNameException, p.first.c_str());
        }
        r = sqlite3_bind_text(stmt, c, p.second.c_str(), -1, SQLITE_TRANSIENT);
        if (r != SQLITE_OK) {
            throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
        }
    }
    int columns = sqlite3_column_count(stmt);
    for (;;) {
        r = sqlite3_step(stmt);
        if (r == SQLITE_DONE) {
            break;
        }
        if (r == SQLITE_ROW) {
            std::vector<Cell> row;
            for (int i = 0; i < columns; i++) {
                row.push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
            }
            rows.push_back(Cell(row));
        } else {
            throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
        }
    }
    sqlite3_finalize(stmt);
    return Cell(rows);
}

bool execOne(void *db, const std::string &sql, const std::map<utf8string, utf8string> &parameters, Cell *result)
{
    sqlite3_stmt *stmt;
    int r = sqlite3_prepare_v2(static_cast<sqlite3 *>(db), sql.c_str(), -1, &stmt, NULL);
    if (r != SQLITE_OK) {
        throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
    }
    for (auto p: parameters) {
        int c = sqlite3_bind_parameter_index(stmt, p.first.c_str());
        if (c == 0) {
            throw RtlException(Exception_ParameterNameException, p.first.c_str());
        }
        r = sqlite3_bind_text(stmt, c, p.second.c_str(), -1, SQLITE_TRANSIENT);
        if (r != SQLITE_OK) {
            throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
        }
    }
    int columns = sqlite3_column_count(stmt);
    r = sqlite3_step(stmt);
    if (r == SQLITE_DONE) {
        //fprintf(stderr, "sqlite no data: %s\n", sql.c_str());
        return false;
    }
    if (r == SQLITE_ROW) {
        for (int i = 0; i < columns; i++) {
            result->array_for_write().push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
        }
    } else {
        throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
    }
    sqlite3_finalize(stmt);
    return true;
}

Cell execRaw(void *db, const std::string &sql)
{
    std::vector<Cell> rows;
    char *errmsg;
    int r = sqlite3_exec(static_cast<sqlite3 *>(db), sql.c_str(), callback, &rows, &errmsg);
    if (r != SQLITE_OK) {
        throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
    }
    return Cell(rows);
}

void close(void *db)
{
    sqlite3_close(static_cast<sqlite3 *>(db));
}

class Cursor {
public:
    Cursor(sqlite3 *db, const std::string &query): db(db), query(query), stmt(nullptr), columns(0) {}
    virtual ~Cursor() {}
    void open()
    {
        int r = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
        if (r != SQLITE_OK) {
            throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
        }
        columns = sqlite3_column_count(stmt);
    }
    bool fetch(Cell *result)
    {
        int r = sqlite3_step(stmt);
        if (r == SQLITE_DONE) {
            //fprintf(stderr, "sqlite no data: %s\n", sql.c_str());
            return false;
        }
        if (r == SQLITE_ROW) {
            for (int i = 0; i < columns; i++) {
                result->array_for_write().push_back(Cell(reinterpret_cast<const char *>(sqlite3_column_text(stmt, i))));
            }
        } else {
            throw RtlException(global::Exception_SqlException, sqlite3_errmsg(static_cast<sqlite3 *>(db)), r);
        }
        return true;
    }
    void close()
    {
        sqlite3_finalize(stmt);
    }

    sqlite3 *db;
    const std::string query;
    sqlite3_stmt *stmt;
    int columns;
private:
    Cursor(const Cursor &);
    Cursor &operator=(const Cursor &);
};

std::map<std::string, std::unique_ptr<Cursor>> Cursors;

std::string cursorDeclare(void *db, const std::string &name, const std::string &query)
{
    Cursors[name] = std::unique_ptr<Cursor> { new Cursor(static_cast<sqlite3 *>(db), query) };
    return name;
}

void cursorOpen(const std::string &name)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    c->second->open();
}

bool cursorFetch(const std::string &name, Cell *result)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    return c->second->fetch(result);
}

void cursorClose(const std::string &name)
{
    auto c = Cursors.find(name);
    if (c == Cursors.end()) {
        throw RtlException(global::Exception_SqlException, name);
    }
    c->second->close();
    Cursors.erase(c);
}

} // namespace sqlite

} // namespace rtl
<|endoftext|>


<commit_before>#include <AndroidLog.h>
#include <Android.h>
#include <unistd.h>

#include "ExampleAndroidHandler.h"

extern "C"
{
	void android_main();
}

void android_main()
{
	LOGV( "[Example]: android_main() called!" );

	// Create the handler
	ExampleAndroidHandler* pHandler = new ExampleAndroidHandler();

	// Set the event handler
	Android::SetEventHandler( pHandler );

	// Run!
	pHandler->Run();

	// Application over
	// Note the handler is destroy by Android
}
<commit_msg>Moved delete responsibility of Handler to user<commit_after>#include <AndroidLog.h>
#include <Android.h>
#include <unistd.h>

#include "ExampleAndroidHandler.h"

extern "C"
{
	void android_main();
}

void android_main()
{
	LOGV( "[Example]: android_main() called!" );

	// Create the handler
	ExampleAndroidHandler* pHandler = new ExampleAndroidHandler();

	// Set the event handler
	Android::SetEventHandler( pHandler );

	// Run!
	pHandler->Run();

	// Application over
	delete pHandler;

}
<|endoftext|>