<commit_before>#pragma once

#include <Communicator.hpp>
#include <Addressing.hpp>
#include <Collective.hpp>
#include <ParallelLoop.hpp>
#include <GlobalAllocator.hpp>
#include <Delegate.hpp>
#include <AsyncDelegate.hpp>
#include <Array.hpp>
#include "TupleGraph.hpp"

#include <algorithm>

// #define USE_MPI3_COLLECTIVES
#undef USE_MPI3_COLLECTIVES
#ifdef USE_MPI3_COLLECTIVES
#include <mpi.h>
#endif

namespace Grappa {

  struct Vertex {
    int64_t * local_adj; // adjacencies that are local
    int64_t nadj;        // number of adjacencies
    int64_t local_sz;    // size of local allocation (regardless of how full it is)
    // int64_t parent;
    void * vertex_data;

    Vertex(): local_adj(nullptr), nadj(0), local_sz(0) {}
    ~Vertex() {}

    template< typename F >
    void forall_adj(F body) {
      for (int64_t i=0; i<nadj; i++) {
        body(local_adj[i]);
      }
    }

    auto adj_iter() -> decltype(util::iterate(local_adj)) { return util::iterate(local_adj, nadj); }
  };

  // vertex with parent
  struct VertexP : public Vertex {
    VertexP(): Vertex() { parent(-1); }
    int64_t parent() { return (int64_t)vertex_data; }
    void parent(int64_t parent) { vertex_data = (void*)parent; }
  };

  template< class V = Vertex >
  struct Graph {
    static_assert(block_size % sizeof(V) == 0, "V size not evenly divisible into blocks!");

    // // Helpers (for if we go with custom cyclic distribution)
    // inline Core    vertex_owner (int64_t v) { return v % cores(); }
    // inline int64_t vertex_offset(int64_t v) { return v / cores(); }

    // Fields
    GlobalAddress<V> vs;
    int64_t nv, nadj, nadj_local;

    // Internal fields
    int64_t * adj_buf;
    int64_t * scratch;

    GlobalAddress<Graph> self;

    Graph(GlobalAddress<Graph> self, GlobalAddress<V> vs, int64_t nv)
      : self(self)
      , vs(vs)
      , nv(nv)
      , nadj(0)
      , nadj_local(0)
      , adj_buf(nullptr)
      , scratch(nullptr)
    { }

    ~Graph() {
      for (V& v : iterate_local(vs, nv)) { v.~V(); }
      if (adj_buf) locale_free(adj_buf);
    }

    void destroy() {
      auto self = this->self;
      global_free(this->vs);
      call_on_all_cores([self]{ self->~Graph(); });
      global_free(self);
    }

    template< int LEVEL = 0 >
    static void dump(GlobalAddress<Graph> g) {
      for (int64_t i=0; i<g->nv; i++) {
        delegate::call(g->vs+i, [i](V * v){
          std::stringstream ss;
          ss << "<" << i << ">";
          for (int64_t i=0; i<v->nadj; i++) ss << " " << v->local_adj[i];
          VLOG(LEVEL) << ss.str();
        });
      }
    }

    /// Cast graph to new type, and allow user to re-initialize each V by providing a
    /// functor (the body of a forall() over the vertices)
    template< typename VNew, typename VOld, typename InitFunc = decltype(nullptr) >
    static GlobalAddress<Graph<VNew>> transform_vertices(GlobalAddress<Graph<VOld>> o, InitFunc init) {
      static_assert(sizeof(VNew) == sizeof(V), "transformed vertex size must be the unchanged.");
      auto g = static_cast<GlobalAddress<Graph<VNew>>>(o);
      forall(g->vs, g->nv, init);
      return g;
    }

    // Constructor
    static GlobalAddress<Graph> create(const TupleGraph& tg, bool directed = false) {
      double t;
      auto g = symmetric_global_alloc<Graph<V>>();

      // find nv
          t = walltime();
      forall(tg.edges, tg.nedge, [g](TupleGraph::Edge& e){
        if (e.v0 > g->nv) { g->nv = e.v0; }
        if (e.v1 > g->nv) { g->nv = e.v1; }
      });
      on_all_cores([g]{
        g->nv = Grappa::allreduce<int64_t,collective_max>(g->nv) + 1;
      });
          VLOG(1) << "find_nv_time: " << walltime() - t;

      auto vs = global_alloc<V>(g->nv);
      auto self = g;
      on_all_cores([g,vs]{
        new (g.localize()) Graph(g, vs, g->nv);
        for (V& v : iterate_local(g->vs, g->nv)) {
          new (&v) V();
        }

    #ifdef SMALL_GRAPH
        // g->scratch = locale_alloc<int64_t>(g->nv);
        if (locale_mycore() == 0) g->scratch = locale_alloc<int64_t>(g->nv);
        barrier();
        if (locale_mycore() == 0) {
          memset(g->scratch, 0, sizeof(int64_t)*g->nv);
        } else {
          g->scratch = delegate::call(mylocale()*locale_cores(), [g]{ return g->scratch; });
        }
        VLOG(0) << "locale = " << mylocale() << ", scratch = " << g->scratch;
    #endif
      });
                                                                t = walltime();
      // count the outgoing/undirected edges per vertex
      forall(tg.edges, tg.nedge, [g,directed](TupleGraph::Edge& e){
        CHECK_LT(e.v0, g->nv); CHECK_LT(e.v1, g->nv);
    #ifdef SMALL_GRAPH
        // g->scratch[e.v0]++;
        // if (!directed) g->scratch[e.v1]++;
        __sync_fetch_and_add(g->scratch+e.v0, 1);
        if (!directed) __sync_fetch_and_add(g->scratch+e.v1, 1);
    #else
        auto count = [](GlobalAddress<V> v){
          delegate::call<SyncMode::Async>(v.core(), [v]{ v->local_sz++; });
        };
        count(g->vs+e.v0);
        if (!directed) count(g->vs+e.v1);
    #endif
      });
      VLOG(1) << "count_time: " << walltime() - t;

    #ifdef SMALL_GRAPH
      t = walltime();
    #ifdef USE_MPI3_COLLECTIVES
      on_all_cores([g]{
        MPI_Request r; int done;
        MPI_Iallreduce(MPI_IN_PLACE, g->scratch, g->nv, MPI_INT64_T, MPI_SUM, MPI_COMM_WORLD, &r);
        do {
          MPI_Test( &r, &done, MPI_STATUS_IGNORE );
          if(!done) { Grappa::yield(); }
        } while(!done);
      });
    #else
      on_all_cores([g]{ allreduce_inplace<int64_t,collective_add>(g->scratch, g->nv); });
    #endif // USE_MPI3_COLLECTIVES
      VLOG(1) << "allreduce_inplace_time: " << walltime() - t;
      // on_all_cores([g]{ VLOG(5) << util::array_str("scratch", g->scratch, g->nv, 25); });
    #endif // SMALL_GRAPH

      // allocate space for each vertex's adjacencies (+ duplicates)
      forall(g->vs, g->nv, [g](int64_t i, V& v) {
    #ifdef SMALL_GRAPH
        // adjust b/c allreduce didn't account for having 1 instance per locale
        v.local_sz = g->scratch[i] / locale_cores();
    #endif

        v.nadj = 0;
        if (v.local_sz > 0) v.local_adj = new int64_t[v.local_sz];
      });
      VLOG(3) << "after adj allocs";

      // scatter
      forall(tg.edges, tg.nedge, [g,directed](TupleGraph::Edge& e){
        auto scatter = [g](int64_t vi, int64_t adj) {
          auto vaddr = g->vs+vi;
          delegate::call<SyncMode::Async>(vaddr.core(), [vaddr,adj]{
            auto& v = *vaddr.pointer();
            v.local_adj[v.nadj++] = adj;
          });
        };
        scatter(e.v0, e.v1);
        if (!directed) scatter(e.v1, e.v0);
      });
      VLOG(3) << "after scatter, nv = " << g->nv;

      // sort & de-dup
      forall(g->vs, g->nv, [g](int64_t vi, V& v){
        CHECK_EQ(v.nadj, v.local_sz);
        std::sort(v.local_adj, v.local_adj+v.nadj);

        int64_t tail = 0;
        for (int64_t i=0; i<v.nadj; i++, tail++) {
          v.local_adj[tail] = v.local_adj[i];
          while (v.local_adj[tail] == v.local_adj[i+1]) i++;
        }
        v.nadj = tail;
        // VLOG(0) << "<" << vi << ">" << util::array_str("", v.local_adj, v.nadj);
        g->nadj_local += v.nadj;
      });
      VLOG(3) << "after sort";

      // compact
      on_all_cores([g]{
    #ifdef SMALL_GRAPH
        if (locale_mycore() == 0) locale_free(g->scratch);
    #endif

        VLOG(2) << "nadj_local = " << g->nadj_local;

        // allocate storage for local vertices' adjacencies
        g->adj_buf = locale_alloc<int64_t>(g->nadj_local);
        // compute total nadj
        g->nadj = allreduce<int64_t,collective_add>(g->nadj_local);

        int64_t * adj = g->adj_buf;
        for (V& v : iterate_local(g->vs, g->nv)) {
          Grappa::memcpy(adj, v.local_adj, v.nadj);
          if (v.local_sz > 0) delete[] v.local_adj;
          v.local_sz = v.nadj;
          v.local_adj = adj;
          adj += v.nadj;
        }
        CHECK_EQ(adj - g->adj_buf, g->nadj_local);
      });

      return g;
    }

  } GRAPPA_BLOCK_ALIGNED;

  namespace impl {
    template< GlobalCompletionEvent * C, int64_t Threshold, typename V, typename F >
    void forall(GlobalAddress<Graph<V>> g, F loop_body, void (F::*mf)(Vertex&) const) {
      forall<C,Threshold>(g->vs, g->nv, loop_body);
    }

    /// Demonstrating another "visitor" we could provide for graphs (this is kinda
    /// silly as it just gives you the indices of each edge).
    template< GlobalCompletionEvent * C, int64_t Threshold, typename V, typename F >
    void forall(GlobalAddress<Graph<V>> g, F loop_body, void (F::*mf)(int64_t src, int64_t dst) const) {
      forall<C,Threshold>(g->vs, g->nv, [loop_body](int64_t i, V& v){
        for (auto j : v.adj_iter()) {
          loop_body(i, j);
        }
      });
    }

  }

  template< GlobalCompletionEvent * C = &impl::local_gce,
            int64_t Threshold = impl::USE_LOOP_THRESHOLD_FLAG,
            typename V = decltype(nullptr),
            typename F = decltype(nullptr) >
  void forall(GlobalAddress<Graph<V>> g, F loop_body) {
    impl::forall<C,Threshold>(g, loop_body, &F::operator());
  }

} // namespace Grappa<commit_msg>comments detailing a bunch of potential forall overloads for graphs<commit_after>#pragma once

#include <Communicator.hpp>
#include <Addressing.hpp>
#include <Collective.hpp>
#include <ParallelLoop.hpp>
#include <GlobalAllocator.hpp>
#include <Delegate.hpp>
#include <AsyncDelegate.hpp>
#include <Array.hpp>
#include "TupleGraph.hpp"

#include <algorithm>

// #define USE_MPI3_COLLECTIVES
#undef USE_MPI3_COLLECTIVES
#ifdef USE_MPI3_COLLECTIVES
#include <mpi.h>
#endif

namespace Grappa {

  struct Vertex {
    int64_t * local_adj; // adjacencies that are local
    int64_t nadj;        // number of adjacencies
    int64_t local_sz;    // size of local allocation (regardless of how full it is)
    // int64_t parent;
    void * vertex_data;

    Vertex(): local_adj(nullptr), nadj(0), local_sz(0) {}
    ~Vertex() {}

    template< typename F >
    void forall_adj(F body) {
      for (int64_t i=0; i<nadj; i++) {
        body(local_adj[i]);
      }
    }

    auto adj_iter() -> decltype(util::iterate(local_adj)) { return util::iterate(local_adj, nadj); }
  };

  // vertex with parent
  struct VertexP : public Vertex {
    VertexP(): Vertex() { parent(-1); }
    int64_t parent() { return (int64_t)vertex_data; }
    void parent(int64_t parent) { vertex_data = (void*)parent; }
  };

  template< class V = Vertex >
  struct Graph {
    static_assert(block_size % sizeof(V) == 0, "V size not evenly divisible into blocks!");

    // // Helpers (for if we go with custom cyclic distribution)
    // inline Core    vertex_owner (int64_t v) { return v % cores(); }
    // inline int64_t vertex_offset(int64_t v) { return v / cores(); }

    // Fields
    GlobalAddress<V> vs;
    int64_t nv, nadj, nadj_local;

    // Internal fields
    int64_t * adj_buf;
    int64_t * scratch;

    GlobalAddress<Graph> self;

    Graph(GlobalAddress<Graph> self, GlobalAddress<V> vs, int64_t nv)
      : self(self)
      , vs(vs)
      , nv(nv)
      , nadj(0)
      , nadj_local(0)
      , adj_buf(nullptr)
      , scratch(nullptr)
    { }

    ~Graph() {
      for (V& v : iterate_local(vs, nv)) { v.~V(); }
      if (adj_buf) locale_free(adj_buf);
    }

    void destroy() {
      auto self = this->self;
      global_free(this->vs);
      call_on_all_cores([self]{ self->~Graph(); });
      global_free(self);
    }

    template< int LEVEL = 0 >
    static void dump(GlobalAddress<Graph> g) {
      for (int64_t i=0; i<g->nv; i++) {
        delegate::call(g->vs+i, [i](V * v){
          std::stringstream ss;
          ss << "<" << i << ">";
          for (int64_t i=0; i<v->nadj; i++) ss << " " << v->local_adj[i];
          VLOG(LEVEL) << ss.str();
        });
      }
    }

    /// Cast graph to new type, and allow user to re-initialize each V by providing a
    /// functor (the body of a forall() over the vertices)
    template< typename VNew, typename VOld, typename InitFunc = decltype(nullptr) >
    static GlobalAddress<Graph<VNew>> transform_vertices(GlobalAddress<Graph<VOld>> o, InitFunc init) {
      static_assert(sizeof(VNew) == sizeof(V), "transformed vertex size must be the unchanged.");
      auto g = static_cast<GlobalAddress<Graph<VNew>>>(o);
      forall(g->vs, g->nv, init);
      return g;
    }

    // Constructor
    static GlobalAddress<Graph> create(const TupleGraph& tg, bool directed = false) {
      double t;
      auto g = symmetric_global_alloc<Graph<V>>();

      // find nv
          t = walltime();
      forall(tg.edges, tg.nedge, [g](TupleGraph::Edge& e){
        if (e.v0 > g->nv) { g->nv = e.v0; }
        if (e.v1 > g->nv) { g->nv = e.v1; }
      });
      on_all_cores([g]{
        g->nv = Grappa::allreduce<int64_t,collective_max>(g->nv) + 1;
      });
          VLOG(1) << "find_nv_time: " << walltime() - t;

      auto vs = global_alloc<V>(g->nv);
      auto self = g;
      on_all_cores([g,vs]{
        new (g.localize()) Graph(g, vs, g->nv);
        for (V& v : iterate_local(g->vs, g->nv)) {
          new (&v) V();
        }

    #ifdef SMALL_GRAPH
        // g->scratch = locale_alloc<int64_t>(g->nv);
        if (locale_mycore() == 0) g->scratch = locale_alloc<int64_t>(g->nv);
        barrier();
        if (locale_mycore() == 0) {
          memset(g->scratch, 0, sizeof(int64_t)*g->nv);
        } else {
          g->scratch = delegate::call(mylocale()*locale_cores(), [g]{ return g->scratch; });
        }
        VLOG(0) << "locale = " << mylocale() << ", scratch = " << g->scratch;
    #endif
      });
                                                                t = walltime();
      // count the outgoing/undirected edges per vertex
      forall(tg.edges, tg.nedge, [g,directed](TupleGraph::Edge& e){
        CHECK_LT(e.v0, g->nv); CHECK_LT(e.v1, g->nv);
    #ifdef SMALL_GRAPH
        // g->scratch[e.v0]++;
        // if (!directed) g->scratch[e.v1]++;
        __sync_fetch_and_add(g->scratch+e.v0, 1);
        if (!directed) __sync_fetch_and_add(g->scratch+e.v1, 1);
    #else
        auto count = [](GlobalAddress<V> v){
          delegate::call<SyncMode::Async>(v.core(), [v]{ v->local_sz++; });
        };
        count(g->vs+e.v0);
        if (!directed) count(g->vs+e.v1);
    #endif
      });
      VLOG(1) << "count_time: " << walltime() - t;

    #ifdef SMALL_GRAPH
      t = walltime();
    #ifdef USE_MPI3_COLLECTIVES
      on_all_cores([g]{
        MPI_Request r; int done;
        MPI_Iallreduce(MPI_IN_PLACE, g->scratch, g->nv, MPI_INT64_T, MPI_SUM, MPI_COMM_WORLD, &r);
        do {
          MPI_Test( &r, &done, MPI_STATUS_IGNORE );
          if(!done) { Grappa::yield(); }
        } while(!done);
      });
    #else
      on_all_cores([g]{ allreduce_inplace<int64_t,collective_add>(g->scratch, g->nv); });
    #endif // USE_MPI3_COLLECTIVES
      VLOG(1) << "allreduce_inplace_time: " << walltime() - t;
      // on_all_cores([g]{ VLOG(5) << util::array_str("scratch", g->scratch, g->nv, 25); });
    #endif // SMALL_GRAPH

      // allocate space for each vertex's adjacencies (+ duplicates)
      forall(g->vs, g->nv, [g](int64_t i, V& v) {
    #ifdef SMALL_GRAPH
        // adjust b/c allreduce didn't account for having 1 instance per locale
        v.local_sz = g->scratch[i] / locale_cores();
    #endif

        v.nadj = 0;
        if (v.local_sz > 0) v.local_adj = new int64_t[v.local_sz];
      });
      VLOG(3) << "after adj allocs";

      // scatter
      forall(tg.edges, tg.nedge, [g,directed](TupleGraph::Edge& e){
        auto scatter = [g](int64_t vi, int64_t adj) {
          auto vaddr = g->vs+vi;
          delegate::call<SyncMode::Async>(vaddr.core(), [vaddr,adj]{
            auto& v = *vaddr.pointer();
            v.local_adj[v.nadj++] = adj;
          });
        };
        scatter(e.v0, e.v1);
        if (!directed) scatter(e.v1, e.v0);
      });
      VLOG(3) << "after scatter, nv = " << g->nv;

      // sort & de-dup
      forall(g->vs, g->nv, [g](int64_t vi, V& v){
        CHECK_EQ(v.nadj, v.local_sz);
        std::sort(v.local_adj, v.local_adj+v.nadj);

        int64_t tail = 0;
        for (int64_t i=0; i<v.nadj; i++, tail++) {
          v.local_adj[tail] = v.local_adj[i];
          while (v.local_adj[tail] == v.local_adj[i+1]) i++;
        }
        v.nadj = tail;
        // VLOG(0) << "<" << vi << ">" << util::array_str("", v.local_adj, v.nadj);
        g->nadj_local += v.nadj;
      });
      VLOG(3) << "after sort";

      // compact
      on_all_cores([g]{
    #ifdef SMALL_GRAPH
        if (locale_mycore() == 0) locale_free(g->scratch);
    #endif

        VLOG(2) << "nadj_local = " << g->nadj_local;

        // allocate storage for local vertices' adjacencies
        g->adj_buf = locale_alloc<int64_t>(g->nadj_local);
        // compute total nadj
        g->nadj = allreduce<int64_t,collective_add>(g->nadj_local);

        int64_t * adj = g->adj_buf;
        for (V& v : iterate_local(g->vs, g->nv)) {
          Grappa::memcpy(adj, v.local_adj, v.nadj);
          if (v.local_sz > 0) delete[] v.local_adj;
          v.local_sz = v.nadj;
          v.local_adj = adj;
          adj += v.nadj;
        }
        CHECK_EQ(adj - g->adj_buf, g->nadj_local);
      });

      return g;
    }

  } GRAPPA_BLOCK_ALIGNED;

  namespace impl {
    template< GlobalCompletionEvent * C, int64_t Threshold, typename V, typename F >
    void forall(GlobalAddress<Graph<V>> g, F loop_body, void (F::*mf)(Vertex&) const) {
      forall<C,Threshold>(g->vs, g->nv, loop_body);
    }

    /// Demonstrating another "visitor" we could provide for graphs (this is kinda
    /// silly as it just gives you the indices of each edge).
    template< GlobalCompletionEvent * C, int64_t Threshold, typename V, typename F >
    void forall(GlobalAddress<Graph<V>> g, F loop_body, void (F::*mf)(int64_t src, int64_t dst) const) {
      forall<C,Threshold>(g->vs, g->nv, [loop_body](int64_t i, V& v){
        for (auto j : v.adj_iter()) {
          loop_body(i, j);
        }
      });
    }

  }

  template< GlobalCompletionEvent * C = &impl::local_gce,
            int64_t Threshold = impl::USE_LOOP_THRESHOLD_FLAG,
            typename V = decltype(nullptr),
            typename F = decltype(nullptr) >
  void forall(GlobalAddress<Graph<V>> g, F loop_body) {
    impl::forall<C,Threshold>(g, loop_body, &F::operator());
  }

  ///////////////////////////////////////////////////
  // proposed forall overloads for Graph iteration
  ///////////////////////////////////////////////////
  // forall(g, [](int64_t i, Vertex& v){
  //
  // });
  //
  // forall(adj(src_v), [](GlobalAddress<Vertex> vj){
  //
  // });
  // forall(adj(src_v), [](int64_t j, GlobalAddress<Vertex> vj){
  //
  // });
  //
  // // run *at* the end vertex
  // forall(src_v.adj(), [](Vertex& ev){
  //   // delegate
  // });
  //
  // forall(g, [](GlobalAddress<Vertex> s, GlobalAddress<Vertex> e){
  //   // runs wherever
  // });
  //
  // forall(g, [](Vertex& s, GlobalAddress<Vertex> e){
  //   // runs on first Vertex
  // });
  //
  // forall(g, [](GlobalAddress<Vertex> s, Vertex& e){
  //   // runs on other Vertex
  //   // (how to do this w/o making a spawn per vertex?)
  // });
  //
  // forall(g, [](const Vertex& s, Vertex& e){
  //   // runs where 'e' is, caches source vertices somehow?
  //   // how the hell to run this efficiently????
  // });
  //

} // namespace Grappa<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2004 by Allan Sandfeld Jensen
    email                : kde@carewolf.com
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
 *   USA                                                                   *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevectorlist.h>
#include <tdebug.h>

#include "apeitem.h"

using namespace TagLib;
using namespace APE;

class APE::Item::ItemPrivate
{
public:
  ItemPrivate() : type(Text), readOnly(false) {}

  Item::ItemTypes type;
  String key;
  ByteVector value;
  StringList text;
  bool readOnly;
};

APE::Item::Item()
{
  d = new ItemPrivate;
}

APE::Item::Item(const String &key, const String &value)
{
  d = new ItemPrivate;
  d->key = key;
  d->text.append(value);
}

APE::Item::Item(const String &key, const StringList &values)
{
  d = new ItemPrivate;
  d->key = key;
  d->text = values;
}

APE::Item::Item(const Item &item)
{
  d = new ItemPrivate(*item.d);
}

APE::Item::~Item()
{
  delete d;
}

Item &APE::Item::operator=(const Item &item)
{
  delete d;
  d = new ItemPrivate(*item.d);
  return *this;
}

void APE::Item::setReadOnly(bool readOnly)
{
  d->readOnly = readOnly;
}

bool APE::Item::isReadOnly() const
{
  return d->readOnly;
}

void APE::Item::setType(APE::Item::ItemTypes val)
{
  d->type = val;
}

APE::Item::ItemTypes APE::Item::type() const
{
  return d->type;
}

String APE::Item::key() const
{
  return d->key;
}

ByteVector APE::Item::value() const
{
  // This seems incorrect as it won't be actually rendering the value to keep it
  // up to date.

  return d->value;
}

void APE::Item::setKey(const String &key)
{
    d->key = key;
}

void APE::Item::setValue(const String &value)
{
    d->text = value;
}

void APE::Item::setValues(const StringList &value)
{
    d->text = value;
}

void APE::Item::appendValue(const String &value)
{
    d->text.append(value);
}

void APE::Item::appendValues(const StringList &values)
{
    d->text.append(values);
}

int APE::Item::size() const
{
  return 8 + d->key.size() + 1 + d->value.size();
}

StringList APE::Item::toStringList() const
{
  return d->text;
}

StringList APE::Item::values() const
{
  return d->text;
}

String APE::Item::toString() const
{
  return isEmpty() ? String::null : d->text.front();
}

bool APE::Item::isEmpty() const
{
  switch(d->type) {
    case 0:
    case 1:
      if(d->text.isEmpty())
        return true;
      if(d->text.size() == 1 && d->text.front().isEmpty())
        return true;
      return false;
    case 2:
      return d->value.isEmpty();
    default:
      return false;
  }
}

void APE::Item::parse(const ByteVector &data)
{
  // 11 bytes is the minimum size for an APE item

  if(data.size() < 11) {
    debug("APE::Item::parse() -- no data in item");
    return;
  }

  uint valueLength  = data.mid(0, 4).toUInt(false);
  uint flags        = data.mid(4, 4).toUInt(false);

  d->key = String(data.mid(8), String::UTF8);

  d->value = data.mid(8 + d->key.size() + 1, valueLength);

  setReadOnly(flags & 1);
  setType(ItemTypes((flags >> 1) & 3));

  if(int(d->type) < 2)
    d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
}

ByteVector APE::Item::render() const
{
  ByteVector data;
  TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
  ByteVector value;

  if(isEmpty())
    return data;

  if(d->type != Item::Binary) {
    StringList::ConstIterator it = d->text.begin();
    value.append(it->data(String::UTF8));
    it++;
    for(; it != d->text.end(); ++it) {
      value.append('\0');
      value.append(it->data(String::UTF8));
    }
    d->value = value;
  }
  else
    value.append(d->value);

  data.append(ByteVector::fromUInt(value.size(), false));
  data.append(ByteVector::fromUInt(flags, false));
  data.append(d->key.data(String::UTF8));
  data.append(ByteVector('\0'));
  data.append(value);

  return data;
}
<commit_msg>Don't try to access the string list if the item type is a locator.<commit_after>/***************************************************************************
    copyright            : (C) 2004 by Allan Sandfeld Jensen
    email                : kde@carewolf.com
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
 *   USA                                                                   *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevectorlist.h>
#include <tdebug.h>

#include "apeitem.h"

using namespace TagLib;
using namespace APE;

class APE::Item::ItemPrivate
{
public:
  ItemPrivate() : type(Text), readOnly(false) {}

  Item::ItemTypes type;
  String key;
  ByteVector value;
  StringList text;
  bool readOnly;
};

APE::Item::Item()
{
  d = new ItemPrivate;
}

APE::Item::Item(const String &key, const String &value)
{
  d = new ItemPrivate;
  d->key = key;
  d->text.append(value);
}

APE::Item::Item(const String &key, const StringList &values)
{
  d = new ItemPrivate;
  d->key = key;
  d->text = values;
}

APE::Item::Item(const Item &item)
{
  d = new ItemPrivate(*item.d);
}

APE::Item::~Item()
{
  delete d;
}

Item &APE::Item::operator=(const Item &item)
{
  delete d;
  d = new ItemPrivate(*item.d);
  return *this;
}

void APE::Item::setReadOnly(bool readOnly)
{
  d->readOnly = readOnly;
}

bool APE::Item::isReadOnly() const
{
  return d->readOnly;
}

void APE::Item::setType(APE::Item::ItemTypes val)
{
  d->type = val;
}

APE::Item::ItemTypes APE::Item::type() const
{
  return d->type;
}

String APE::Item::key() const
{
  return d->key;
}

ByteVector APE::Item::value() const
{
  // This seems incorrect as it won't be actually rendering the value to keep it
  // up to date.

  return d->value;
}

void APE::Item::setKey(const String &key)
{
    d->key = key;
}

void APE::Item::setValue(const String &value)
{
    d->text = value;
}

void APE::Item::setValues(const StringList &value)
{
    d->text = value;
}

void APE::Item::appendValue(const String &value)
{
    d->text.append(value);
}

void APE::Item::appendValues(const StringList &values)
{
    d->text.append(values);
}

int APE::Item::size() const
{
  return 8 + d->key.size() + 1 + d->value.size();
}

StringList APE::Item::toStringList() const
{
  return d->text;
}

StringList APE::Item::values() const
{
  return d->text;
}

String APE::Item::toString() const
{
  return isEmpty() ? String::null : d->text.front();
}

bool APE::Item::isEmpty() const
{
  switch(d->type) {
    case Text:
    case Binary:
      if(d->text.isEmpty())
        return true;
      if(d->text.size() == 1 && d->text.front().isEmpty())
        return true;
      return false;
    case Locator:
      return d->value.isEmpty();
    default:
      return false;
  }
}

void APE::Item::parse(const ByteVector &data)
{
  // 11 bytes is the minimum size for an APE item

  if(data.size() < 11) {
    debug("APE::Item::parse() -- no data in item");
    return;
  }

  uint valueLength  = data.mid(0, 4).toUInt(false);
  uint flags        = data.mid(4, 4).toUInt(false);

  d->key = String(data.mid(8), String::UTF8);

  d->value = data.mid(8 + d->key.size() + 1, valueLength);

  setReadOnly(flags & 1);
  setType(ItemTypes((flags >> 1) & 3));

  if(int(d->type) < 2)
    d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
}

ByteVector APE::Item::render() const
{
  ByteVector data;
  TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
  ByteVector value;

  if(isEmpty())
    return data;

  if(d->type == Text) {
    StringList::ConstIterator it = d->text.begin();

    value.append(it->data(String::UTF8));
    it++;
    for(; it != d->text.end(); ++it) {
      value.append('\0');
      value.append(it->data(String::UTF8));
    }
    d->value = value;
  }
  else
    value.append(d->value);

  data.append(ByteVector::fromUInt(value.size(), false));
  data.append(ByteVector::fromUInt(flags, false));
  data.append(d->key.data(String::UTF8));
  data.append(ByteVector('\0'));
  data.append(value);

  return data;
}
<|endoftext|>


<commit_before>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2014 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  app/oglplus/01.cpp                                                              */
/*  project    :                                                                                */
/*  description:  liberated from oglplus example '007_glm_boxes.cpp'                              */
/*                                                                                */
/**************************************************************************************************/

// includes, system

#include <GL/glew.h> // ::glew*

#include <boost/filesystem.hpp>    // boost::filesystem::path
#include <oglplus/all.hpp>
#include <oglplus/opt/resources.hpp>
#include <oglplus/shapes/cube.hpp>

#include <glm/glm.hpp>
#include <oglplus/interop/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

// includes, project

#include <platform/glut/application/base.hpp>
#include <platform/glut/window/simple.hpp>
#include <platform/oglplus/application.hpp>

#define UKACHULLDCS_USE_TRACE
#undef UKACHULLDCS_USE_TRACE
#include <support/trace.hpp>

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  class window : public platform::glut::window::simple {

    using inherited = platform::glut::window::simple;
    using rect      = platform::window::rect;

  public:

    explicit window(std::string const& a, rect const& b, std::string const& c)
      : inherited     (a, b),
        ctx_          (),
        prg_          (),
        make_cube_    (),
        cube_instr_   (make_cube_.Instructions()),
        cube_indices_ (make_cube_.Indices()),
        frame_time_   (prg_, "Time")
    {
      TRACE("<unnamed>::window::window");

      using namespace oglplus;

      {
        namespace bfs = boost::filesystem;

        bfs::path const   p(c);
        std::string const d(p.parent_path().string());
        std::string const f(p.filename().string());

        ResourceFile      vs_src(d + "/../share/shader/glsl", f, ".vs.glsl");
        ResourceFile      fs_src(d + "/../share/shader/glsl", f, ".fs.glsl");

        prg_ << VertexShader().Source(GLSLSource::FromStream(vs_src.stream()))
             << FragmentShader().Source(GLSLSource::FromStream(fs_src.stream()));

        prg_.Link().Use();
      }

      cube_va_.Bind();

      positions_.Bind(Buffer::Target::Array);
      {
        std::vector<GLfloat> data;
        GLfloat              size(make_cube_.Positions(data));

        Buffer::Data(Buffer::Target::Array, data);

        VertexArrayAttrib attr(prg_, "Position");

        attr.Setup<GLfloat>(size);
        attr.Enable();
      }

      normals_.Bind(Buffer::Target::Array);
      {
        std::vector<GLfloat> data;
        GLfloat              size(make_cube_.Normals(data));

        Buffer::Data(Buffer::Target::Array, data);

        VertexArrayAttrib attr(prg_, "Normal");

        attr.Setup<GLfloat>(size);
        attr.Enable();
      }

      ctx_.ClearColor(0.95f, 0.95f, 0.95f, 0.0f);
      ctx_.ClearDepth(1.0f);
      ctx_.Enable(Capability::DepthTest);

      Typechecked<Uniform<glm::vec3>>  (prg_, "LightPos").
        Set(glm::vec3(7.0, 3.0, -1.0));

      Typechecked<Uniform<glm::mat4x4>>(prg_, "ScaleMatrix").
        Set(glm::scale(glm::mat4(1.0),
                       glm::vec3(1.0, 0.3, 1.7)));
    }

    virtual ~window()
    {
      TRACE("<unnamed>::window::~window");
    }

  private:

    virtual void frame_render_one()
    {
      TRACE("<unnamed>::window::frame_render_one");

      ctx_.Clear().ColorBuffer().DepthBuffer();

      {
        using namespace std::chrono;

        frame_time_.
          Set(duration_cast<duration<double>>(support::clock::now().time_since_epoch()).count());
      }

      cube_instr_.Draw(cube_indices_, 36);
    }

    virtual void reshape(glm::ivec2 const& size)
    {
      TRACE("<unnamed>::window::reshape");

      ctx_.Viewport(size.x, size.y);

      auto camera(glm::perspective(53.0f*3.1415f/180.f,
                                   float(size.x)/float(size.y),
                                   1.0f, 100.0f) *
                  glm::lookAt(glm::vec3(21.0f, 8.0f, 7.0f),
                              glm::vec3( 0.0f, 0.0f, 0.0f),
                              glm::vec3( 0.0f, 1.0f, 0.0f)));

      oglplus::Uniform<glm::mat4x4>(prg_, "CameraMatrix").Set(camera);
    }

    oglplus::Context                       ctx_;
    oglplus::Program                       prg_;
    oglplus::shapes::Cube                  make_cube_;
    oglplus::shapes::DrawingInstructions   cube_instr_;
    oglplus::shapes::Cube::IndexArray      cube_indices_;
    oglplus::VertexArray                   cube_va_;
    oglplus::Buffer                        positions_;
    oglplus::Buffer                        normals_;
    oglplus::Lazy<oglplus::Uniform<float>> frame_time_;

  };

  class application : public platform::glut::application::base {

    using command_line = platform::application::command_line;
    using inherited    = platform::glut::application::base;
    using rect         = platform::window::rect;

  public:

    explicit application(command_line const& a)
      : inherited(a),
        window_  (nullptr)
    {
      TRACE("<unnamed>::application::application");
    }

    virtual ~application()
    {
      TRACE("<unnamed>::application::~application");
    }

    virtual void process_command_line()
    {
      TRACE("<unnamed>::application::process_command_line");

      inherited::process_command_line();

      window_.reset(new window(command_line_.argv0, rect(100, 100, 800, 600), command_line_.argv0));
    }

  private:

    std::unique_ptr<window> window_;

  };

  // variables, internal

  // functions, internal

} // namespace {

int
main(int argc, char const* argv[])
{
  TRACE("main");

  namespace pa  = platform::application;
  namespace poa = platform::oglplus::application;

  return poa::execute<application>(pa::command_line(argc, argv), std::nothrow);
}
<commit_msg>using: signal handling<commit_after>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2014 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  app/oglplus/01.cpp                                                              */
/*  project    :                                                                                */
/*  description:  liberated from oglplus example '007_glm_boxes.cpp'                              */
/*                                                                                */
/**************************************************************************************************/

// includes, system

#include <GL/glew.h> // ::glew*

#include <boost/filesystem.hpp>    // boost::filesystem::path
#include <oglplus/all.hpp>
#include <oglplus/opt/resources.hpp>
#include <oglplus/shapes/cube.hpp>

#include <glm/glm.hpp>
#include <oglplus/interop/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

// includes, project

#include <platform/glut/application/base.hpp>
#include <platform/glut/window/simple.hpp>
#include <platform/oglplus/application.hpp>
#include <support/signal_handler.hpp>

#define UKACHULLDCS_USE_TRACE
#undef UKACHULLDCS_USE_TRACE
#include <support/trace.hpp>

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  class window : public platform::glut::window::simple {

    using inherited = platform::glut::window::simple;
    using rect      = platform::window::rect;

  public:

    explicit window(std::string const& a, rect const& b, std::string const& c)
      : inherited     (a, b),
        ctx_          (),
        prg_          (),
        make_cube_    (),
        cube_instr_   (make_cube_.Instructions()),
        cube_indices_ (make_cube_.Indices()),
        frame_time_   (prg_, "Time")
    {
      TRACE("<unnamed>::window::window");

      using namespace oglplus;

      {
        namespace bfs = boost::filesystem;

        bfs::path const   p(c);
        std::string const d(p.parent_path().string());
        std::string const f(p.filename().string());

        ResourceFile      vs_src(d + "/../share/shader/glsl", f, ".vs.glsl");
        ResourceFile      fs_src(d + "/../share/shader/glsl", f, ".fs.glsl");

        prg_ << VertexShader().Source(GLSLSource::FromStream(vs_src.stream()))
             << FragmentShader().Source(GLSLSource::FromStream(fs_src.stream()));

        prg_.Link().Use();
      }

      cube_va_.Bind();

      positions_.Bind(Buffer::Target::Array);
      {
        std::vector<GLfloat> data;
        GLfloat              size(make_cube_.Positions(data));

        Buffer::Data(Buffer::Target::Array, data);

        VertexArrayAttrib attr(prg_, "Position");

        attr.Setup<GLfloat>(size);
        attr.Enable();
      }

      normals_.Bind(Buffer::Target::Array);
      {
        std::vector<GLfloat> data;
        GLfloat              size(make_cube_.Normals(data));

        Buffer::Data(Buffer::Target::Array, data);

        VertexArrayAttrib attr(prg_, "Normal");

        attr.Setup<GLfloat>(size);
        attr.Enable();
      }

      ctx_.ClearColor(0.95f, 0.95f, 0.95f, 0.0f);
      ctx_.ClearDepth(1.0f);
      ctx_.Enable(Capability::DepthTest);

      Typechecked<Uniform<glm::vec3>>  (prg_, "LightPos").
        Set(glm::vec3(7.0, 3.0, -1.0));

      Typechecked<Uniform<glm::mat4x4>>(prg_, "ScaleMatrix").
        Set(glm::scale(glm::mat4(1.0),
                       glm::vec3(1.0, 0.3, 1.7)));
    }

    virtual ~window()
    {
      TRACE("<unnamed>::window::~window");
    }

  private:

    virtual void frame_render_one()
    {
      TRACE_NEVER("<unnamed>::window::frame_render_one");

      ctx_.Clear().ColorBuffer().DepthBuffer();

      {
        using namespace std::chrono;

        frame_time_.
          Set(duration_cast<duration<double>>(support::clock::now().time_since_epoch()).count());
      }

      cube_instr_.Draw(cube_indices_, 36);
    }

    virtual void reshape(glm::ivec2 const& size)
    {
      TRACE("<unnamed>::window::reshape");

      ctx_.Viewport(size.x, size.y);

      auto camera(glm::perspective(53.0f*3.1415f/180.f,
                                   float(size.x)/float(size.y),
                                   1.0f, 100.0f) *
                  glm::lookAt(glm::vec3(21.0f, 8.0f, 7.0f),
                              glm::vec3( 0.0f, 0.0f, 0.0f),
                              glm::vec3( 0.0f, 1.0f, 0.0f)));

      oglplus::Uniform<glm::mat4x4>(prg_, "CameraMatrix").Set(camera);
    }

    oglplus::Context                       ctx_;
    oglplus::Program                       prg_;
    oglplus::shapes::Cube                  make_cube_;
    oglplus::shapes::DrawingInstructions   cube_instr_;
    oglplus::shapes::Cube::IndexArray      cube_indices_;
    oglplus::VertexArray                   cube_va_;
    oglplus::Buffer                        positions_;
    oglplus::Buffer                        normals_;
    oglplus::Lazy<oglplus::Uniform<float>> frame_time_;

  };

  class application : public platform::glut::application::base {

    using command_line = platform::application::command_line;
    using inherited    = platform::glut::application::base;
    using rect         = platform::window::rect;

  public:

    static void terminate(::siginfo_t* a)
    {
      TRACE("<unnamed>::application::terminate");

      inherited::terminate = true;

      std::cout << '\n'
                << "terminating by user request ('"
                << ::strsignal(a->si_signo) << "' " << a->si_signo << ")"
                << '\n';
    }

    explicit application(command_line const& a)
      : inherited(a),
        window_  (nullptr)
    {
      TRACE("<unnamed>::application::application");
    }

    virtual ~application()
    {
      TRACE("<unnamed>::application::~application");
    }

    virtual void process_command_line()
    {
      TRACE("<unnamed>::application::process_command_line");

      inherited::process_command_line();

      window_.reset(new window(command_line_.argv0, rect(100, 100, 800, 600), command_line_.argv0));
    }

  private:

    std::unique_ptr<window> window_;

  };

  // variables, internal

  // functions, internal

} // namespace {

int
main(int argc, char const* argv[])
{
  TRACE("main");

  using support::signal_handler;

  signal_handler::instance->handler(SIGINT,  &application::terminate);
  signal_handler::instance->handler(SIGTERM, &application::terminate);

  namespace pa  = platform::application;
  namespace poa = platform::oglplus::application;

  return poa::execute<application>(pa::command_line(argc, argv), std::nothrow);
}
<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>
#include <math.h>

using std::vector;
using namespace Halide;
using namespace Halide::Internal;

class CountInterleaves : public IRVisitor {
public:
    int result;
    CountInterleaves() : result(0) {}

    using IRVisitor::visit;

    void visit(const Call *op) {
        if (op->name == Call::interleave_vectors &&
            op->call_type == Call::Intrinsic) {
            result++;
        }
        IRVisitor::visit(op);
    }
};

int count_interleaves(Func f) {
    Target t = get_jit_target_from_environment();
    t.set_feature(Target::NoBoundsQuery);
    t.set_feature(Target::NoAsserts);
    Stmt s = Internal::lower(f.function(), t);
    CountInterleaves i;
    s.accept(&i);
    return i.result;
}

void check_interleave_count(Func f, int correct) {
    int c = count_interleaves(f);
    if (c != correct) {
        printf("Func %s should have interleaved %d times but interleaved %d times instead.\n",
               f.name().c_str(), correct, c);
        exit(-1);
    }
}

// Make sure the interleave pattern generates good vector code

int main(int argc, char **argv) {
    Var x, y, c;

    {
        Func f, g, h;
        f(x) = sin(x);
        g(x) = cos(x);
        h(x) = select(x % 2 == 0, 1.0f/f(x/2), g(x/2)*17.0f);

        f.compute_root();
        g.compute_root();
        h.vectorize(x, 8);

        check_interleave_count(h, 1);

        Image<float> result = h.realize(16);
        for (int x = 0; x < 16; x++) {
            float correct = ((x % 2) == 0) ? (1.0f/(sinf(x/2))) : (cosf(x/2)*17.0f);
            float delta = result(x) - correct;
            if (delta > 0.01 || delta < -0.01) {
                printf("result(%d) = %f instead of %f\n", x, result(x), correct);
                return -1;
            }
        }
    }

    {
        // Test interleave 3 vectors:
        Func planar, interleaved;
        planar(x, y) = Halide::cast<float>( 3 * x + y );
        interleaved(x, y) = planar(x, y);

        Var xy("xy");
        planar
            .compute_at(interleaved, xy)
            .vectorize(x, 4);

        interleaved
            .reorder(y, x)
            .bound(y, 0, 3)
            .bound(x, 0, 16)
            .fuse(y, x, xy)
            .vectorize(xy, 12);

        interleaved
            .output_buffer()
            .set_min(1, 0)
            .set_stride(0, 3)
            .set_stride(1, 1)
            .set_extent(1, 3);

        Buffer buff3;
        buff3 = Buffer(Float(32), 16, 3, 0, 0, (uint8_t *)0);
        buff3.raw_buffer()->stride[0] = 3;
        buff3.raw_buffer()->stride[1] = 1;

        Realization r3(Internal::vec(buff3));
        interleaved.realize(r3);

        check_interleave_count(interleaved, 2);

        Image<float> result3 = r3[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 3; y++) {
                float correct = 3*x + y;
                float delta = result3(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result3(x,y), correct);
                    return -1;
                }
            }
        }
    }

    {
        // Test interleave 4 vectors:
        Func f1, f2, f3, f4, f5;
        f1(x) = sin(x);
        f2(x) = sin(2*x);
        f3(x) = sin(3*x);
        f4(x) = sin(4*x);
        f5(x) = sin(5*x);

        Func output4;
        output4(x, y) = select(y == 0, f1(x),
                               y == 1, f2(x),
                               y == 2, f3(x),
                               f4(x));

        output4
            .reorder(y, x)
            .bound(y, 0, 4)
            .unroll(y)
            .vectorize(x, 4);

        output4.output_buffer()
            .set_min(1, 0)
            .set_stride(0, 4)
            .set_stride(1, 1)
            .set_extent(1, 4);

        check_interleave_count(output4, 1);

        Buffer buff4;
        buff4 = Buffer(Float(32), 16, 4, 0, 0, (uint8_t *)0);
        buff4.raw_buffer()->stride[0] = 4;
        buff4.raw_buffer()->stride[1] = 1;

        Realization r4(Internal::vec(buff4));
        output4.realize(r4);

        Image<float> result4 = r4[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 4; y++) {
                float correct = sin((y+1)*x);
                float delta = result4(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result4(x,y), correct);
                    return -1;
                }
            }
        }

        // Test interleave 5 vectors:
        Func output5;
        output5(x, y) = select(y == 0, f1(x),
                               y == 1, f2(x),
                               y == 2, f3(x),
                               y == 3, f4(x),
                               f5(x));

        output5
            .reorder(y, x)
            .bound(y, 0, 5)
            .unroll(y)
            .vectorize(x, 4);

        output5.output_buffer()
            .set_min(1, 0)
            .set_stride(0, 5)
            .set_stride(1, 1)
            .set_extent(1, 5);

        check_interleave_count(output5, 1);

        Buffer buff5;
        buff5 = Buffer(Float(32), 16, 5, 0, 0, (uint8_t *)0);
        buff5.raw_buffer()->stride[0] = 5;
        buff5.raw_buffer()->stride[1] = 1;

        Realization r5(Internal::vec(buff5));
        output5.realize(r5);

        Image<float> result5 = r5[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 5; y++) {
                float correct = sin((y+1)*x);
                float delta = result5(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result5(x,y), correct);
                    return -1;
                }
            }
        }
    }

    {
        // Test interleaving inside of nested blocks
        Func f1, f2, f3, f4, f5;
        f1(x) = sin(x);
        f1.compute_root();

        f2(x) = sin(2*x);
        f2.compute_root();

        Func unrolled;
        unrolled(x, y) = select(x % 2 == 0, f1(x), f2(x)) + y;

        Var xi, yi;
        unrolled.tile(x, y, xi, yi, 2, 2).vectorize(x, 4).unroll(xi).unroll(yi).unroll(x, 2);

        check_interleave_count(unrolled, 4);
    }

    {
        // Make sure we don't interleave when the reordering would change the meaning.
        Image<uint8_t> ref;
        for (int i = 0; i < 2; i++) {
            Func output6;
            output6(x, y) = cast<uint8_t>(x);
            RDom r(0, 16);

            // A not-safe-to-merge pair of updates
            output6(2*r, 0) = cast<uint8_t>(3);
            output6(2*r+1, 0) = output6(2*r, 0)+2;

            // A safe-to-merge pair of updates
            output6(2*r, 1) = cast<uint8_t>(3);
            output6(2*r+1, 1) = cast<uint8_t>(4);

            // A safe-to-merge-but-not-complete triple of updates:
            output6(3*r, 3) = cast<uint8_t>(3);
            output6(3*r+1, 3) = cast<uint8_t>(4);

            // A safe-to-merge-but-we-don't pair of updates, because they
            // load recursively, so we conservatively bail out.
            output6(2*r, 2) += 1;
            output6(2*r+1, 2) += 2;

            // A safe-to-merge triple of updates:
            output6(3*r, 3) = cast<uint8_t>(7);
            output6(3*r+2, 3) = cast<uint8_t>(9);
            output6(3*r+1, 3) = cast<uint8_t>(8);

            if (i == 0) {
                // Making the reference output.
                ref = output6.realize(50, 4);
            } else {
                // Vectorize and compare to the reference.
                for (int j = 0; j < 11; j++) {
                    output6.update(j).vectorize(r);
                }

                check_interleave_count(output6, 2);

                Image<uint8_t> out = output6.realize(50, 4);
                for (int y = 0; y < ref.height(); y++) {
                    for (int x = 0; x < ref.width(); x++) {
                        if (out(x, y) != ref(x, y)) {
                            printf("result(%d, %d) = %d instead of %d\n",
                                   x, y, out(x, y), ref(x, y));
                            return -1;
                        }
                    }
                }
            }
        }
    }

    {
        // Test that transposition works when vectorizing either dimension:
        Func square("square");
        square(x, y) = cast(UInt(16), 5*x + y);

        Func trans1("trans1");
        trans1(x, y) = square(y, x);

        Func trans2("trans2");
        trans2(x, y) = square(y, x);

        square.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8);

        trans1.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8)
            .vectorize(x)
            .unroll(y);

        trans2.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8)
            .unroll(x)
            .vectorize(y);

        trans1.output_buffer()
            .set_min(0,0).set_min(1,0)
            .set_stride(0,1).set_stride(1,8)
            .set_extent(0,8).set_extent(1,8);

        trans2.output_buffer()
            .set_min(0,0).set_min(1,0)
            .set_stride(0,1).set_stride(1,8)
            .set_extent(0,8).set_extent(1,8);

        Image<uint16_t> result6(8,8);
        Image<uint16_t> result7(8,8);
        trans1.realize(result6);
        trans2.realize(result7);

        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                int correct = 5*y + x;
                if (result6(x,y) != correct) {
                    printf("result(%d) = %d instead of %d\n", x, result6(x,y), correct);
                    return -1;
                }

                if (result7(x,y) != correct) {
                    printf("result(%d) = %d instead of %d\n", x, result7(x,y), correct);
                    return -1;
                }
            }
        }

        check_interleave_count(trans1, 1);
        check_interleave_count(trans2, 1);
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Modified interleave test to account for loop splitting<commit_after>#include "Halide.h"
#include <stdio.h>
#include <math.h>

using std::vector;
using namespace Halide;
using namespace Halide::Internal;

class CountInterleaves : public IRVisitor {
public:
    int result;
    CountInterleaves() : result(0) {}

    using IRVisitor::visit;

    void visit(const Call *op) {
        if (op->name == Call::interleave_vectors &&
            op->call_type == Call::Intrinsic) {
            result++;
        }
        IRVisitor::visit(op);
    }
};

int count_interleaves(Func f) {
    Target t = get_jit_target_from_environment();
    t.set_feature(Target::NoBoundsQuery);
    t.set_feature(Target::NoAsserts);
    Stmt s = Internal::lower(f.function(), t);
    CountInterleaves i;
    s.accept(&i);
    return i.result;
}

void check_interleave_count(Func f, int correct) {
    int c = count_interleaves(f);
    if (c < correct) {
        printf("Func %s should have interleaved >= %d times but interleaved %d times instead.\n",
               f.name().c_str(), correct, c);
        exit(-1);
    }
}

// Make sure the interleave pattern generates good vector code

int main(int argc, char **argv) {
    Var x, y, c;

    {
        Func f, g, h;
        f(x) = sin(x);
        g(x) = cos(x);
        h(x) = select(x % 2 == 0, 1.0f/f(x/2), g(x/2)*17.0f);

        f.compute_root();
        g.compute_root();
        h.vectorize(x, 8);

        check_interleave_count(h, 1);

        Image<float> result = h.realize(16);
        for (int x = 0; x < 16; x++) {
            float correct = ((x % 2) == 0) ? (1.0f/(sinf(x/2))) : (cosf(x/2)*17.0f);
            float delta = result(x) - correct;
            if (delta > 0.01 || delta < -0.01) {
                printf("result(%d) = %f instead of %f\n", x, result(x), correct);
                return -1;
            }
        }
    }

    {
        // Test interleave 3 vectors:
        Func planar, interleaved;
        planar(x, y) = Halide::cast<float>( 3 * x + y );
        interleaved(x, y) = planar(x, y);

        Var xy("xy");
        planar
            .compute_at(interleaved, xy)
            .vectorize(x, 4);

        interleaved
            .reorder(y, x)
            .bound(y, 0, 3)
            .bound(x, 0, 16)
            .fuse(y, x, xy)
            .vectorize(xy, 12);

        interleaved
            .output_buffer()
            .set_min(1, 0)
            .set_stride(0, 3)
            .set_stride(1, 1)
            .set_extent(1, 3);

        Buffer buff3;
        buff3 = Buffer(Float(32), 16, 3, 0, 0, (uint8_t *)0);
        buff3.raw_buffer()->stride[0] = 3;
        buff3.raw_buffer()->stride[1] = 1;

        Realization r3(Internal::vec(buff3));
        interleaved.realize(r3);

        check_interleave_count(interleaved, 2);

        Image<float> result3 = r3[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 3; y++) {
                float correct = 3*x + y;
                float delta = result3(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result3(x,y), correct);
                    return -1;
                }
            }
        }
    }

    {
        // Test interleave 4 vectors:
        Func f1, f2, f3, f4, f5;
        f1(x) = sin(x);
        f2(x) = sin(2*x);
        f3(x) = sin(3*x);
        f4(x) = sin(4*x);
        f5(x) = sin(5*x);

        Func output4;
        output4(x, y) = select(y == 0, f1(x),
                               y == 1, f2(x),
                               y == 2, f3(x),
                               f4(x));

        output4
            .reorder(y, x)
            .bound(y, 0, 4)
            .unroll(y)
            .vectorize(x, 4);

        output4.output_buffer()
            .set_min(1, 0)
            .set_stride(0, 4)
            .set_stride(1, 1)
            .set_extent(1, 4);

        check_interleave_count(output4, 1);

        Buffer buff4;
        buff4 = Buffer(Float(32), 16, 4, 0, 0, (uint8_t *)0);
        buff4.raw_buffer()->stride[0] = 4;
        buff4.raw_buffer()->stride[1] = 1;

        Realization r4(Internal::vec(buff4));
        output4.realize(r4);

        Image<float> result4 = r4[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 4; y++) {
                float correct = sin((y+1)*x);
                float delta = result4(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result4(x,y), correct);
                    return -1;
                }
            }
        }

        // Test interleave 5 vectors:
        Func output5;
        output5(x, y) = select(y == 0, f1(x),
                               y == 1, f2(x),
                               y == 2, f3(x),
                               y == 3, f4(x),
                               f5(x));

        output5
            .reorder(y, x)
            .bound(y, 0, 5)
            .unroll(y)
            .vectorize(x, 4);

        output5.output_buffer()
            .set_min(1, 0)
            .set_stride(0, 5)
            .set_stride(1, 1)
            .set_extent(1, 5);

        check_interleave_count(output5, 1);

        Buffer buff5;
        buff5 = Buffer(Float(32), 16, 5, 0, 0, (uint8_t *)0);
        buff5.raw_buffer()->stride[0] = 5;
        buff5.raw_buffer()->stride[1] = 1;

        Realization r5(Internal::vec(buff5));
        output5.realize(r5);

        Image<float> result5 = r5[0];
        for (int x = 0; x < 16; x++) {
            for (int y = 0; y < 5; y++) {
                float correct = sin((y+1)*x);
                float delta = result5(x,y) - correct;
                if (delta > 0.01 || delta < -0.01) {
                    printf("result(%d) = %f instead of %f\n", x, result5(x,y), correct);
                    return -1;
                }
            }
        }
    }

    {
        // Test interleaving inside of nested blocks
        Func f1, f2, f3, f4, f5;
        f1(x) = sin(x);
        f1.compute_root();

        f2(x) = sin(2*x);
        f2.compute_root();

        Func unrolled;
        unrolled(x, y) = select(x % 2 == 0, f1(x), f2(x)) + y;

        Var xi, yi;
        unrolled.tile(x, y, xi, yi, 2, 2).vectorize(x, 4).unroll(xi).unroll(yi).unroll(x, 2);

        check_interleave_count(unrolled, 4);
    }

    {
        // Make sure we don't interleave when the reordering would change the meaning.
        Image<uint8_t> ref;
        for (int i = 0; i < 2; i++) {
            Func output6;
            output6(x, y) = cast<uint8_t>(x);
            RDom r(0, 16);

            // A not-safe-to-merge pair of updates
            output6(2*r, 0) = cast<uint8_t>(3);
            output6(2*r+1, 0) = output6(2*r, 0)+2;

            // A safe-to-merge pair of updates
            output6(2*r, 1) = cast<uint8_t>(3);
            output6(2*r+1, 1) = cast<uint8_t>(4);

            // A safe-to-merge-but-not-complete triple of updates:
            output6(3*r, 3) = cast<uint8_t>(3);
            output6(3*r+1, 3) = cast<uint8_t>(4);

            // A safe-to-merge-but-we-don't pair of updates, because they
            // load recursively, so we conservatively bail out.
            output6(2*r, 2) += 1;
            output6(2*r+1, 2) += 2;

            // A safe-to-merge triple of updates:
            output6(3*r, 3) = cast<uint8_t>(7);
            output6(3*r+2, 3) = cast<uint8_t>(9);
            output6(3*r+1, 3) = cast<uint8_t>(8);

            if (i == 0) {
                // Making the reference output.
                ref = output6.realize(50, 4);
            } else {
                // Vectorize and compare to the reference.
                for (int j = 0; j < 11; j++) {
                    output6.update(j).vectorize(r);
                }

                check_interleave_count(output6, 2);

                Image<uint8_t> out = output6.realize(50, 4);
                for (int y = 0; y < ref.height(); y++) {
                    for (int x = 0; x < ref.width(); x++) {
                        if (out(x, y) != ref(x, y)) {
                            printf("result(%d, %d) = %d instead of %d\n",
                                   x, y, out(x, y), ref(x, y));
                            return -1;
                        }
                    }
                }
            }
        }
    }

    {
        // Test that transposition works when vectorizing either dimension:
        Func square("square");
        square(x, y) = cast(UInt(16), 5*x + y);

        Func trans1("trans1");
        trans1(x, y) = square(y, x);

        Func trans2("trans2");
        trans2(x, y) = square(y, x);

        square.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8);

        trans1.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8)
            .vectorize(x)
            .unroll(y);

        trans2.compute_root()
            .bound(x, 0, 8)
            .bound(y, 0, 8)
            .unroll(x)
            .vectorize(y);

        trans1.output_buffer()
            .set_min(0,0).set_min(1,0)
            .set_stride(0,1).set_stride(1,8)
            .set_extent(0,8).set_extent(1,8);

        trans2.output_buffer()
            .set_min(0,0).set_min(1,0)
            .set_stride(0,1).set_stride(1,8)
            .set_extent(0,8).set_extent(1,8);

        Image<uint16_t> result6(8,8);
        Image<uint16_t> result7(8,8);
        trans1.realize(result6);
        trans2.realize(result7);

        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                int correct = 5*y + x;
                if (result6(x,y) != correct) {
                    printf("result(%d) = %d instead of %d\n", x, result6(x,y), correct);
                    return -1;
                }

                if (result7(x,y) != correct) {
                    printf("result(%d) = %d instead of %d\n", x, result7(x,y), correct);
                    return -1;
                }
            }
        }

        check_interleave_count(trans1, 1);
        check_interleave_count(trans2, 1);
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>#include "Halide.h"

#include "../performance/benchmark.h"

using namespace Halide;

void dump_asm(Func f) {
    Target t;
    t.from_string("host-no_runtime-no_asserts-no_bounds_query");
    f.compile_to_assembly("/dev/stdout", {}, t);
}

int main(int argc, char **argv) {
    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x-1, y) + f(x, y) + f(x+1, y);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x-4, y) + f(x, y) + f(x+4, y);

        g.vectorize(x, 4);

        g.realize(100, 100);
    }

    {
        Func f, g, h;
        Var x, y;
        f(x, y) = x + y;
        h(x, y) = x + y;
        g(x, y) = f(x-1, y) + f(x, y) + f(x+1, y) + h(x, y);

        f.compute_root();
        h.compute_at(g, x);

        dump_asm(g);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(min(100, x-1), y) + f(min(100, x), y) + f(min(100, x+1), y);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(clamp(f(x-1, y), 0, 100), y) + f(clamp(f(x, y), 0, 100), y);

        g.realize(100, 100);
    }

    {
        // A case where the index is lifted out into a let
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-y*2), y) + f((x-y*2)+1, y) + f((x-y*2)+2, y);

        g.realize(100, 100);
    }

    {
        // A case where the index and a load are both lifted out into a let
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-y*2), y) + f((x-y*2)+1, y) + f((x-y*2)+2, y) + f((x-y*2)+2, y);

        g.realize(100, 100);
    }

    if (0) {
        // A case where there's a combinatorially large Expr going on.
        Func f, g;
        Var x, y;

        Expr idx = 0;
        for (int i = 0; i < 20; i++) {
            idx += y;
            idx *= idx;
        }

        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-idx), y) + f((x-idx)+1, y) + f((x-idx)+2, y);

        // Don't send it to LLVM. LLVM has its own problems with these Exprs.
        g.compile_to_module({}, "g");
    }

    {
        // A case with an inner loop.
        Func f, g;
        Var x, y, c;

        f(x, y) = x + y;
        f.compute_root();
        g(c, x, y) = f(x, y) + f(x+1, y) + f(x+2, y) + c;
        g.bound(c, 0, 3).unroll(c).unroll(x, 2);

        g.realize(3, 100, 100);
    }

    {
        // A case with weirdly-spaced taps
        Func f, g;
        Var x, y;

        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x, y) + f(x+1, y) + f(x+3, y);

        g.realize(100, 100);
    }

    {
        // A case with far too many entries to keep around
        Func f, g, h;
        Var x, y, c;

        f(c, x, y) = c + x + y;
        f.compute_root();

        g(c, x, y) = f(c, x-2, y) + f(c, x-1, y) + f(c, x, y) + f(c, x+1, y) + f(c, x+2, y);
        h(c, x, y) = g(c, x, y-2) + g(c, x, y-1) + g(c, x, y) + g(c, x, y+1) + g(c, x, y+2) + f(c, x-3, y);

        h.bound(c, 0, 4).vectorize(c);

        dump_asm(h);

        h.realize(4, 100, 100);

        Image<int> out(4, 1000, 1000);
        double t = benchmark(10, 10, [&]{h.realize(out);});
        printf("%f\n", t);
    }

    if (get_jit_target_from_environment().has_gpu_feature()) {
        // Reusing values from local memory on the GPU is much better
        // than reloading from shared or global.
        Func f, g, h;
        Var x, y;

        f(x, y) = cast<float>(x + y);
        f.compute_root();

        g(x, y) = f(x-2, y) + f(x-1, y) + f(x, y) + f(x+1, y) + f(x+2, y);
        Var xo, xi;
        g.split(x, xo, xi, 16).gpu_tile(xo, y, 8, 8);

        g.realize(160, 100);
    }

    return 0;
}
<commit_msg>Fix incorrect target construction from string.<commit_after>#include "Halide.h"

#include "../performance/benchmark.h"

using namespace Halide;

void dump_asm(Func f) {
    Target t("host-no_runtime-no_asserts-no_bounds_query");
    f.compile_to_assembly("/dev/stdout", {}, t);
}

int main(int argc, char **argv) {
    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x-1, y) + f(x, y) + f(x+1, y);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x-4, y) + f(x, y) + f(x+4, y);

        g.vectorize(x, 4);

        g.realize(100, 100);
    }

    {
        Func f, g, h;
        Var x, y;
        f(x, y) = x + y;
        h(x, y) = x + y;
        g(x, y) = f(x-1, y) + f(x, y) + f(x+1, y) + h(x, y);

        f.compute_root();
        h.compute_at(g, x);

        dump_asm(g);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(min(100, x-1), y) + f(min(100, x), y) + f(min(100, x+1), y);

        g.realize(100, 100);
    }

    {
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(clamp(f(x-1, y), 0, 100), y) + f(clamp(f(x, y), 0, 100), y);

        g.realize(100, 100);
    }

    {
        // A case where the index is lifted out into a let
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-y*2), y) + f((x-y*2)+1, y) + f((x-y*2)+2, y);

        g.realize(100, 100);
    }

    {
        // A case where the index and a load are both lifted out into a let
        Func f, g;
        Var x, y;
        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-y*2), y) + f((x-y*2)+1, y) + f((x-y*2)+2, y) + f((x-y*2)+2, y);

        g.realize(100, 100);
    }

    if (0) {
        // A case where there's a combinatorially large Expr going on.
        Func f, g;
        Var x, y;

        Expr idx = 0;
        for (int i = 0; i < 20; i++) {
            idx += y;
            idx *= idx;
        }

        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f((x-idx), y) + f((x-idx)+1, y) + f((x-idx)+2, y);

        // Don't send it to LLVM. LLVM has its own problems with these Exprs.
        g.compile_to_module({}, "g");
    }

    {
        // A case with an inner loop.
        Func f, g;
        Var x, y, c;

        f(x, y) = x + y;
        f.compute_root();
        g(c, x, y) = f(x, y) + f(x+1, y) + f(x+2, y) + c;
        g.bound(c, 0, 3).unroll(c).unroll(x, 2);

        g.realize(3, 100, 100);
    }

    {
        // A case with weirdly-spaced taps
        Func f, g;
        Var x, y;

        f(x, y) = x + y;
        f.compute_root();
        g(x, y) = f(x, y) + f(x+1, y) + f(x+3, y);

        g.realize(100, 100);
    }

    {
        // A case with far too many entries to keep around
        Func f, g, h;
        Var x, y, c;

        f(c, x, y) = c + x + y;
        f.compute_root();

        g(c, x, y) = f(c, x-2, y) + f(c, x-1, y) + f(c, x, y) + f(c, x+1, y) + f(c, x+2, y);
        h(c, x, y) = g(c, x, y-2) + g(c, x, y-1) + g(c, x, y) + g(c, x, y+1) + g(c, x, y+2) + f(c, x-3, y);

        h.bound(c, 0, 4).vectorize(c);

        dump_asm(h);

        h.realize(4, 100, 100);

        Image<int> out(4, 1000, 1000);
        double t = benchmark(10, 10, [&]{h.realize(out);});
        printf("%f\n", t);
    }

    if (get_jit_target_from_environment().has_gpu_feature()) {
        // Reusing values from local memory on the GPU is much better
        // than reloading from shared or global.
        Func f, g, h;
        Var x, y;

        f(x, y) = cast<float>(x + y);
        f.compute_root();

        g(x, y) = f(x-2, y) + f(x-1, y) + f(x, y) + f(x+1, y) + f(x+2, y);
        Var xo, xi;
        g.split(x, xo, xi, 16).gpu_tile(xo, y, 8, 8);

        g.realize(160, 100);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "Avalanche.h"
#include "login/LoginFlood.h"
#include "attack/AttackRegistry.h"
#include "attack/AttackInteract.h"
#include "attack/AttackBookEdit.h"

#include <fstream>
#include <memory>
#include <iostream>

namespace avalanche {

static const AttackRegistry attackRegistry = AttackRegistry::MethodRegistry {
    { "interact", [](mc::core::Client* client) -> std::unique_ptr<AttackMethod> { return std::make_unique<AttackInteract>(client); } },
    { "bookedit", [](mc::core::Client* client) -> std::unique_ptr<AttackMethod> { return std::make_unique<AttackBookEdit>(client); } },
};

void Avalanche::Run() {
    s32 activeInstances = m_LoginMethod->Login(m_Instances);

    std::vector<bool> instanceStatus(activeInstances, true);

    std::cout << "Successfully logged in " << activeInstances << "/" << m_Instances.size() << " instances." << std::endl;

    while (activeInstances > 0) {
        for (std::size_t i = 0; i < m_Instances.size(); ++i) {
            auto&& instance = m_Instances[i];

            if (!instanceStatus[i]) continue;

            auto state = instance.GetClient()->GetConnection()->GetSocketState();
            if (state != mc::network::Socket::Status::Connected) {
                instanceStatus[i] = false;
                --activeInstances;

                instance.SetAttackMethod(nullptr);

                std::cout << "Instance was kicked from server. " << activeInstances << " instances remaining." << std::endl;
                continue;
            }

            instance.GetClient()->Update();
        }
    }
}

bool Avalanche::Initialize(const OptionMap& options) {
    auto jsonIter = options.find("json");
    Json::Value attackNode;
    std::string attack;
    std::size_t count = 1;

    auto attackIter = options.find("attack");
    if (attackIter != options.end())
        attack = attackIter->second;

    if (jsonIter != options.end()) {
        std::string jsonFile = jsonIter->second;

        Json::Reader reader;
        Json::Value root;

        std::ifstream in(jsonFile);

        if (!in.is_open())
            throw std::runtime_error("Failed to read JSON file " + jsonFile);

        if (!reader.parse(in, root))
            throw std::runtime_error("Failed to parse JSON file " + jsonFile);

        auto&& countNode = root["count"];
        if (countNode.isInt())
            count = countNode.asInt();

        auto&& loginNode = root["login"];
        if (loginNode.isObject()) {
            auto&& methodNode = loginNode["method"];
            std::string methodName = "flood";

            if (methodNode.isObject()) {
                if (methodNode["name"].isString())
                    methodName = methodNode["name"].asString();
            }

            if (methodName == "flood") {
                m_LoginMethod = std::make_unique<avalanche::LoginFlood>();

                m_LoginMethod->ReadJSON(loginNode);
            }
        }

        if (attack.empty()) {
            attackNode = root["attack"];
            if (attackNode.isObject()) {
                auto&& methodNode = attackNode["method"];
                if (methodNode.isString()) {
                    attack = methodNode.asString();
                }
            }
        }
    }

    if (m_LoginMethod == nullptr)
        m_LoginMethod = std::make_unique<avalanche::LoginFlood>();

    if (!m_LoginMethod->ReadOptions(options)) {
        return false;
    }

    auto countIter = options.find("count");
    if (countIter != options.end())
        count = strtol(countIter->second.c_str(), nullptr, 10);

    m_Instances = std::vector<Instance>(count);

    for (auto&& instance : m_Instances) {
        if (!attack.empty()) {
            std::unique_ptr<AttackMethod> attackMethod = attackRegistry.CreateAttack(attack, instance.GetClient());

            if (!attackNode.isNull()) {
                attackMethod->ReadJSON(attackNode);
            }

            instance.SetAttackMethod(std::move(attackMethod));
        }
    }

    return true;
}

} // ns avalanche
<commit_msg>Fix crash when unknown attack method is used<commit_after>#include "Avalanche.h"
#include "login/LoginFlood.h"
#include "attack/AttackRegistry.h"
#include "attack/AttackInteract.h"
#include "attack/AttackBookEdit.h"

#include <fstream>
#include <memory>
#include <iostream>

namespace avalanche {

static const AttackRegistry attackRegistry = AttackRegistry::MethodRegistry {
    { "interact", [](mc::core::Client* client) -> std::unique_ptr<AttackMethod> { return std::make_unique<AttackInteract>(client); } },
    { "bookedit", [](mc::core::Client* client) -> std::unique_ptr<AttackMethod> { return std::make_unique<AttackBookEdit>(client); } },
};

void Avalanche::Run() {
    s32 activeInstances = m_LoginMethod->Login(m_Instances);

    std::vector<bool> instanceStatus(activeInstances, true);

    std::cout << "Successfully logged in " << activeInstances << "/" << m_Instances.size() << " instances." << std::endl;

    while (activeInstances > 0) {
        for (std::size_t i = 0; i < m_Instances.size(); ++i) {
            auto&& instance = m_Instances[i];

            if (!instanceStatus[i]) continue;

            auto state = instance.GetClient()->GetConnection()->GetSocketState();
            if (state != mc::network::Socket::Status::Connected) {
                instanceStatus[i] = false;
                --activeInstances;

                instance.SetAttackMethod(nullptr);

                std::cout << "Instance was kicked from server. " << activeInstances << " instances remaining." << std::endl;
                continue;
            }

            instance.GetClient()->Update();
        }
    }
}

bool Avalanche::Initialize(const OptionMap& options) {
    auto jsonIter = options.find("json");
    Json::Value attackNode;
    std::string attack;
    std::size_t count = 1;

    auto attackIter = options.find("attack");
    if (attackIter != options.end())
        attack = attackIter->second;

    if (jsonIter != options.end()) {
        std::string jsonFile = jsonIter->second;

        Json::Reader reader;
        Json::Value root;

        std::ifstream in(jsonFile);

        if (!in.is_open())
            throw std::runtime_error("Failed to read JSON file " + jsonFile);

        if (!reader.parse(in, root))
            throw std::runtime_error("Failed to parse JSON file " + jsonFile);

        auto&& countNode = root["count"];
        if (countNode.isInt())
            count = countNode.asInt();

        auto&& loginNode = root["login"];
        if (loginNode.isObject()) {
            auto&& methodNode = loginNode["method"];
            std::string methodName = "flood";

            if (methodNode.isObject()) {
                if (methodNode["name"].isString())
                    methodName = methodNode["name"].asString();
            }

            if (methodName == "flood") {
                m_LoginMethod = std::make_unique<avalanche::LoginFlood>();

                m_LoginMethod->ReadJSON(loginNode);
            }
        }

        if (attack.empty()) {
            attackNode = root["attack"];
            if (attackNode.isObject()) {
                auto&& methodNode = attackNode["method"];
                if (methodNode.isString()) {
                    attack = methodNode.asString();
                }
            }
        }
    }

    if (m_LoginMethod == nullptr)
        m_LoginMethod = std::make_unique<avalanche::LoginFlood>();

    if (!m_LoginMethod->ReadOptions(options)) {
        return false;
    }

    auto countIter = options.find("count");
    if (countIter != options.end())
        count = strtol(countIter->second.c_str(), nullptr, 10);

    m_Instances = std::vector<Instance>(count);

    for (auto&& instance : m_Instances) {
        if (!attack.empty()) {
            std::unique_ptr<AttackMethod> attackMethod = attackRegistry.CreateAttack(attack, instance.GetClient());

            if (attackMethod && !attackNode.isNull()) {
                attackMethod->ReadJSON(attackNode);
            }

            instance.SetAttackMethod(std::move(attackMethod));
        }
    }

    return true;
}

} // ns avalanche
<|endoftext|>


<commit_before>#include "../../../YaizuComLib/src/stkpl/StkPl.h"
#include "MyMsgProc.h"
#include "ApiPostUser.h"
#include "dataaccess.h"
#include "..\Global.h"

StkObject* ApiPostUser::ExecuteImpl(StkObject* ReqObj, int Method, wchar_t UrlPath[StkWebAppExec::URL_PATH_LENGTH], int* ResultCode, wchar_t Locale[3], wchar_t* Token)
{
	StkObject* ResObj = new StkObject(L"");

	wchar_t YourName[Global::MAXLEN_OF_USERNAME] = L"";
	if (!CheckCredentials(Token, YourName)) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_AUTH_ERROR, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_AUTH_ERROR), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_AUTH_ERROR));
		*ResultCode = 401;
		return ResObj;
	}

	if (!IsAdminUser(Token)) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR));
		*ResultCode = 403;
		return ResObj;
	}

	if (ReqObj == NULL) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}
	int Id = -1;
	wchar_t Name[Global::MAXLEN_OF_USERNAME] = L"";
	wchar_t Password[Global::MAXLEN_OF_PASSWORD] = L"";
	int Role = -1;
	StkObject* CurObj = ReqObj->GetFirstChildElement();
	if (CurObj == NULL) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}
	while (CurObj) {
		if (StkPlWcsCmp(CurObj->GetName(), L"Id") == 0) {
			Id = CurObj->GetIntValue();
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Name") == 0) {
			if (StkPlWcsLen(CurObj->GetStringValue()) >= Global::MAXLEN_OF_USERNAME) {
				AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG));
				*ResultCode = 400;
				return ResObj;
			}
			StkPlWcsCpy(Name, Global::MAXLEN_OF_USERNAME, CurObj->GetStringValue());
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Password") == 0) {
			if (StkPlWcsLen(CurObj->GetStringValue()) >= Global::MAXLEN_OF_PASSWORD) {
				AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG));
				*ResultCode = 400;
				return ResObj;
			}
			StkPlWcsCpy(Name, Global::MAXLEN_OF_PASSWORD, CurObj->GetStringValue());
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Role") == 0) {
			Role = CurObj->GetIntValue();
		}
		CurObj = CurObj->GetNext();
	}
	if (StkPlWcsCmp(Name, L"") == 0 || Role == -1) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}

	int TmpId = -1;
	wchar_t TmpName[Global::MAXLEN_OF_USERNAME] = L"";
	wchar_t TmpPassword[Global::MAXLEN_OF_PASSWORD] = L"";
	int TmpRole = -1;
	DataAccess::GetInstance()->GetTargetUserById(Id, TmpName, TmpPassword, &TmpRole);
	if (StkPlWcsCmp(YourName, TmpName) == 0) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO));
		*ResultCode = 400;
		return ResObj;
	}
	if (DataAccess::GetInstance()->GetTargetUserByName(Name, &TmpId, TmpPassword, &TmpRole) == true) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST));
		*ResultCode = 400;
		return ResObj;
	}

	if (Id == -1) {
		DataAccess::GetInstance()->AddUser(Name, Role);
		*ResultCode = 200;
		wchar_t LogBufEng[512] = L"";
		wchar_t LogBufJpn[512] = L"";
		StkPlSwPrintf(LogBufEng, 512, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_USER_ADD), Name);
		StkPlSwPrintf(LogBufJpn, 512, MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_USER_ADD), Name);
		DataAccess::GetInstance()->AddLogMsg(LogBufEng, LogBufJpn);
	} else {
		DataAccess::GetInstance()->UpdateUser(Id, Name, Role);
		*ResultCode = 200;
		wchar_t LogBufEng[512] = L"";
		wchar_t LogBufJpn[512] = L"";
		StkPlSwPrintf(LogBufEng, 512, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_USER_EDIT), Name);
		StkPlSwPrintf(LogBufJpn, 512, MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_USER_EDIT), Name);
		DataAccess::GetInstance()->AddLogMsg(LogBufEng, LogBufJpn);
	}

	return ResObj;
}
<commit_msg>#59 : A bug of error handling has been fixed.<commit_after>#include "../../../YaizuComLib/src/stkpl/StkPl.h"
#include "MyMsgProc.h"
#include "ApiPostUser.h"
#include "dataaccess.h"
#include "..\Global.h"

StkObject* ApiPostUser::ExecuteImpl(StkObject* ReqObj, int Method, wchar_t UrlPath[StkWebAppExec::URL_PATH_LENGTH], int* ResultCode, wchar_t Locale[3], wchar_t* Token)
{
	StkObject* ResObj = new StkObject(L"");

	wchar_t YourName[Global::MAXLEN_OF_USERNAME] = L"";
	if (!CheckCredentials(Token, YourName)) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_AUTH_ERROR, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_AUTH_ERROR), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_AUTH_ERROR));
		*ResultCode = 401;
		return ResObj;
	}

	if (!IsAdminUser(Token)) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_ACCESS_RIGHT_ERROR));
		*ResultCode = 403;
		return ResObj;
	}

	if (ReqObj == NULL) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}
	int Id = -1;
	wchar_t Name[Global::MAXLEN_OF_USERNAME] = L"";
	wchar_t Password[Global::MAXLEN_OF_PASSWORD] = L"";
	int Role = -1;
	StkObject* CurObj = ReqObj->GetFirstChildElement();
	if (CurObj == NULL) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}
	while (CurObj) {
		if (StkPlWcsCmp(CurObj->GetName(), L"Id") == 0) {
			Id = CurObj->GetIntValue();
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Name") == 0) {
			if (StkPlWcsLen(CurObj->GetStringValue()) >= Global::MAXLEN_OF_USERNAME) {
				AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG));
				*ResultCode = 400;
				return ResObj;
			}
			StkPlWcsCpy(Name, Global::MAXLEN_OF_USERNAME, CurObj->GetStringValue());
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Password") == 0) {
			if (StkPlWcsLen(CurObj->GetStringValue()) >= Global::MAXLEN_OF_PASSWORD) {
				AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_PARAM_LENGTH_TOO_LONG));
				*ResultCode = 400;
				return ResObj;
			}
			StkPlWcsCpy(Name, Global::MAXLEN_OF_PASSWORD, CurObj->GetStringValue());
		} else if (StkPlWcsCmp(CurObj->GetName(), L"Role") == 0) {
			Role = CurObj->GetIntValue();
		}
		CurObj = CurObj->GetNext();
	}
	if (StkPlWcsCmp(Name, L"") == 0 || Role == -1) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_REQ_NOT_SUFFICIENT));
		*ResultCode = 400;
		return ResObj;
	}

	int TmpId = -1;
	wchar_t TmpName[Global::MAXLEN_OF_USERNAME] = L"";
	wchar_t TmpPassword[Global::MAXLEN_OF_PASSWORD] = L"";
	int TmpRole = -1;
	// In case user information yourself is cahnged.
	DataAccess::GetInstance()->GetTargetUserById(Id, TmpName, TmpPassword, &TmpRole);
	if (StkPlWcsCmp(YourName, TmpName) == 0) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_CANNOT_MODIFY_YOUR_INFO));
		*ResultCode = 400;
		return ResObj;
	}
	// User name is changed, and the name already exists.
	if (StkPlWcsCmp(TmpName, Name) != 0 && DataAccess::GetInstance()->GetTargetUserByName(Name, &TmpId, TmpPassword, &TmpRole) == true) {
		AddCodeAndMsg(ResObj, MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST), MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_SAME_USER_NAME_EXIST));
		*ResultCode = 400;
		return ResObj;
	}

	if (Id == -1) {
		DataAccess::GetInstance()->AddUser(Name, Role);
		*ResultCode = 200;
		wchar_t LogBufEng[512] = L"";
		wchar_t LogBufJpn[512] = L"";
		StkPlSwPrintf(LogBufEng, 512, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_USER_ADD), Name);
		StkPlSwPrintf(LogBufJpn, 512, MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_USER_ADD), Name);
		DataAccess::GetInstance()->AddLogMsg(LogBufEng, LogBufJpn);
	} else {
		DataAccess::GetInstance()->UpdateUser(Id, Name, Role);
		*ResultCode = 200;
		wchar_t LogBufEng[512] = L"";
		wchar_t LogBufJpn[512] = L"";
		StkPlSwPrintf(LogBufEng, 512, MyMsgProc::GetMsgEng(MyMsgProc::CMDFRK_USER_EDIT), Name);
		StkPlSwPrintf(LogBufJpn, 512, MyMsgProc::GetMsgJpn(MyMsgProc::CMDFRK_USER_EDIT), Name);
		DataAccess::GetInstance()->AddLogMsg(LogBufEng, LogBufJpn);
	}

	return ResObj;
}
<|endoftext|>