<commit_before>
/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrBatchedTextContext.h"
#include "GrContext.h"
#include "GrDrawTarget.h"
#include "GrIndexBuffer.h"
#include "GrTextContext.h"

GrBatchedTextContext::GrBatchedTextContext() {
}

GrBatchedTextContext::~GrBatchedTextContext() {
}

void GrBatchedTextContext::init(GrContext* context,
                                const GrPaint& grPaint,
                                const GrMatrix* extMatrix) {
    this->INHERITED::init(context, grPaint, extMatrix);
    fGrPaint = grPaint;
    fDrawTarget = NULL;

    fMaxVertices = 0;
    fCurrTexture = NULL;
    fCurrVertex = 0;
}

void GrBatchedTextContext::finish() {
    GrAssert(fDrawTarget);
    if (fDrawTarget) {
        fDrawTarget->drawState()->disableStages();
    }
    fDrawTarget = NULL;

    this->INHERITED::finish();
}

void GrBatchedTextContext::reset() {
    GrAssert(this->isValid());
    GrAssert(fDrawTarget);
    fDrawTarget->resetVertexSource();
    fMaxVertices = 0;
    fCurrVertex = 0;
    fCurrTexture->unref();
    fCurrTexture = NULL;
}

void GrBatchedTextContext::prepareForGlyph(GrTexture* texture) {
    GrAssert(this->isValid());
    GrAssert(texture);
    if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }
}

void GrBatchedTextContext::setupVertexBuff(void** vertexBuff,
                                           GrVertexLayout vertexLayout) {
    GrAssert(this->isValid());
    GrAssert(fDrawTarget);
    if (NULL == *vertexBuff) {
        // If we need to reserve vertices allow the draw target to suggest
        // a number of verts to reserve and whether to perform a flush.
        fMaxVertices = kMinRequestedVerts;
        bool flush = fDrawTarget->geometryHints(vertexLayout,
                                                &fMaxVertices,
                                                NULL);
        if (flush) {
            this->flush();
            fContext->flush();
            fDrawTarget = fContext->getTextTarget(fGrPaint);
            fMaxVertices = kDefaultRequestedVerts;
            // ignore return, no point in flushing again.
            fDrawTarget->geometryHints(vertexLayout,
                                       &fMaxVertices,
                                       NULL);
        }

        int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
        if (fMaxVertices < kMinRequestedVerts) {
            fMaxVertices = kDefaultRequestedVerts;
        } else if (fMaxVertices > maxQuadVertices) {
            // don't exceed the limit of the index buffer
            fMaxVertices = maxQuadVertices;
        }
        bool success = fDrawTarget->reserveVertexAndIndexSpace(
                                                   vertexLayout,
                                                   fMaxVertices,
                                                   0,
                                                   vertexBuff,
                                                   NULL);
        GrAlwaysAssert(success);
    }
}
<commit_msg>In GrBatchedTextContext, use GrSafeSetNull(), for more safeness!<commit_after>
/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrBatchedTextContext.h"
#include "GrContext.h"
#include "GrDrawTarget.h"
#include "GrIndexBuffer.h"
#include "GrTextContext.h"

GrBatchedTextContext::GrBatchedTextContext() {
}

GrBatchedTextContext::~GrBatchedTextContext() {
}

void GrBatchedTextContext::init(GrContext* context,
                                const GrPaint& grPaint,
                                const GrMatrix* extMatrix) {
    this->INHERITED::init(context, grPaint, extMatrix);
    fGrPaint = grPaint;
    fDrawTarget = NULL;

    fMaxVertices = 0;
    fCurrTexture = NULL;
    fCurrVertex = 0;
}

void GrBatchedTextContext::finish() {
    GrAssert(fDrawTarget);
    if (fDrawTarget) {
        fDrawTarget->drawState()->disableStages();
    }
    fDrawTarget = NULL;

    this->INHERITED::finish();
}

void GrBatchedTextContext::reset() {
    GrAssert(this->isValid());
    GrAssert(fDrawTarget);
    fDrawTarget->resetVertexSource();
    fMaxVertices = 0;
    fCurrVertex = 0;
    GrSafeSetNull(fCurrTexture);
}

void GrBatchedTextContext::prepareForGlyph(GrTexture* texture) {
    GrAssert(this->isValid());
    GrAssert(texture);
    if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }
}

void GrBatchedTextContext::setupVertexBuff(void** vertexBuff,
                                           GrVertexLayout vertexLayout) {
    GrAssert(this->isValid());
    GrAssert(fDrawTarget);
    if (NULL == *vertexBuff) {
        // If we need to reserve vertices allow the draw target to suggest
        // a number of verts to reserve and whether to perform a flush.
        fMaxVertices = kMinRequestedVerts;
        bool flush = fDrawTarget->geometryHints(vertexLayout,
                                                &fMaxVertices,
                                                NULL);
        if (flush) {
            this->flush();
            fContext->flush();
            fDrawTarget = fContext->getTextTarget(fGrPaint);
            fMaxVertices = kDefaultRequestedVerts;
            // ignore return, no point in flushing again.
            fDrawTarget->geometryHints(vertexLayout,
                                       &fMaxVertices,
                                       NULL);
        }

        int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
        if (fMaxVertices < kMinRequestedVerts) {
            fMaxVertices = kDefaultRequestedVerts;
        } else if (fMaxVertices > maxQuadVertices) {
            // don't exceed the limit of the index buffer
            fMaxVertices = maxQuadVertices;
        }
        bool success = fDrawTarget->reserveVertexAndIndexSpace(
                                                   vertexLayout,
                                                   fMaxVertices,
                                                   0,
                                                   vertexBuff,
                                                   NULL);
        GrAlwaysAssert(success);
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2015 Ahnaf Siddiqui

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "D_SDLRenderer2D.h"

#include "D_Log.h"
#include "D_SDLRenderComponent2D.h"
#include "D_SDLTexture.h"
#include "D_Transform2.h"
#include "SDL_image.h"
#include <iostream>

Diamond::SDLRenderer2D::SDLRenderer2D(const Config &config, bool &success)
    : m_window(nullptr), m_renderer(nullptr), m_bgColor({0, 0, 0, 100}),
      m_renderCompPool(config.max_gameobjects_estimate) {
  success = true;

  // Initialize SDL
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
    Log::log("SDL failed to initialize! SDL Error: " +
             std::string(SDL_GetError()));
    success = false;
  }

  // Create window
  m_window = SDL_CreateWindow(
      config.game_name.c_str(), SDL_WINDOWPOS_UNDEFINED,
      SDL_WINDOWPOS_UNDEFINED, config.window_width, config.window_height,
      config.fullscreen || config.window_width <= 0 || config.window_height <= 0
          ? SDL_WINDOW_FULLSCREEN_DESKTOP
          : 0);
  if (m_window == nullptr) {
    Log::log("SDL failed to create window! SDL Error: " +
             std::string(SDL_GetError()));
    success = false;
  }

  // Create renderer
  m_renderer = SDL_CreateRenderer(
      m_window, -1,
      SDL_RENDERER_ACCELERATED |
          (config.vsync ? SDL_RENDERER_PRESENTVSYNC : 0x00000000));
  if (m_renderer == nullptr) {
    Log::log("SDL failed to create renderer! SDL Error: " +
             std::string(SDL_GetError()));
    success = false;
  }

  // Set background color
  m_bgColor = config.bg_color;

  // Initialize image loading
  int img_flags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF;
  if (IMG_Init(img_flags) != img_flags) {
    Log::log("SDL_image failed to initialize! SDL_image Error: " +
             std::string(IMG_GetError()));
    // success = false; // TODO: what's wrong with SDL Image init on Android?
  }

  // Initialize text rendering
  if (TTF_Init() < 0) {
    Log::log("SDL_ttf failed to initialize! SDL_ttf Error: " +
             std::string(TTF_GetError()));
    success = false;
  }

  if (success && config.optimize_render_layers) {
    m_render_objects.resize(config.num_render_layers_estimate);

    for (int i = 0; i < config.num_render_layers_estimate; ++i) {
      m_render_objects[i].data().reserve(config.max_gameobjects_estimate);
    }
  }
}

Diamond::SDLRenderer2D::~SDLRenderer2D() {
  SDL_DestroyRenderer(m_renderer);
  SDL_DestroyWindow(m_window);

  TTF_Quit();
  IMG_Quit();
  SDL_Quit();
}

void Diamond::SDLRenderer2D::renderAll() {
  // Render background
  SDL_SetRenderDrawColor(m_renderer, m_bgColor.r, m_bgColor.g, m_bgColor.b,
                         m_bgColor.a);
  SDL_RenderClear(m_renderer);

  // Render sprites
  for (auto l = m_render_objects.begin(); l != m_render_objects.end(); ++l) {
    for (auto i = l->begin(); i != l->end(); ++i) {
      const auto &transform = i->getTransform();

      auto pivot = i->pivot();
      auto &clip = i->clip();

      pivot.x *= transform.scale.x;
      pivot.y *= transform.scale.y;

      SDL_Rect render_rect = {
          (int)(transform.position.x - pivot.x), // render position x
          (int)(transform.position.y - pivot.y), // render position y
          (int)(clip.w * transform.scale.x),     // render width
          (int)(clip.h * transform.scale.y)      // render height
      };

      // Set transparency
      const auto &color = i->color();
      SDL_SetTextureColorMod(i->texture(), color.r, color.g, color.b);
      SDL_SetTextureAlphaMod(i->texture(), i->alpha());

      SDL_RenderCopyEx(
          m_renderer,         // The SDL backend renderer for this SDL instance.
          i->texture(),       // sprite
          &clip,              // source rect
          &render_rect,       // destination rect
          transform.rotation, // rotation for destination rect in degrees
          &pivot,             // rotation pivot location in local space
          i->getFlip()        // current flip status
          );

      // Reset the texture's transparency before the next render
      SDL_SetTextureColorMod(i->texture(), 255, 255, 255);
      SDL_SetTextureAlphaMod(i->texture(), 255);
    }
  }

  // Render points
  for (SDLRenderablePoint point : m_render_points_queue) {
    SDL_SetRenderDrawColor(m_renderer, point.color.r, point.color.g,
                           point.color.b, point.color.a);

    SDL_RenderDrawPoint(m_renderer, point.coords.x, point.coords.y);
  }

  m_render_points_queue.clear();

  // Render lines
  for (SDLRenderableLine line : m_render_lines_queue) {
    SDL_SetRenderDrawColor(m_renderer, line.color.r, line.color.g, line.color.b,
                           line.color.a);

    SDL_RenderDrawLine(m_renderer, line.p1.x, line.p1.y, line.p2.x, line.p2.y);
  }

  m_render_lines_queue.clear();

  // Update screen
  SDL_RenderPresent(m_renderer);
}

Diamond::Vector2<int> Diamond::SDLRenderer2D::getScreenResolution() const {
  SDL_DisplayMode mode;
  SDL_GetCurrentDisplayMode(0, &mode);
  return Vector2<int>(mode.w, mode.h);
}

Diamond::Vector2<int> Diamond::SDLRenderer2D::getResolution() const {
  Vector2<int> r;
  SDL_GL_GetDrawableSize(m_window, &(r.x), &(r.y));
  return r;
}

int Diamond::SDLRenderer2D::getRefreshRate() const {
  SDL_DisplayMode mode;
  SDL_GetCurrentDisplayMode(0, &mode);
  return mode.refresh_rate;
}

Diamond::DumbPtr<Diamond::Font>
Diamond::SDLRenderer2D::loadFont(const std::string &fontPath, int ptsize) {
  TTF_Font *font = TTF_OpenFont(fontPath.c_str(), ptsize);
  if (!font) {
    Log::log("Failed to load font " + fontPath +
             "! SDL_ttf Error: " + std::string(TTF_GetError()));
    return nullptr;
  }
  return DumbPtr<Font>(new SDLFont(font));
}

Diamond::DumbPtr<Diamond::Texture>
Diamond::SDLRenderer2D::loadTexture(std::string path) {
  SDL_Surface *surface = IMG_Load(path.c_str());
  if (surface == NULL) {
    Log::log("Failed to load image " + path +
             "! SDL_image Error: " + std::string(IMG_GetError()));
    return nullptr;
  }

  SDL_Texture *texture = SDL_CreateTextureFromSurface(m_renderer, surface);
  if (texture == NULL) {
    Log::log("Failed to create texture from " + path +
             "! SDL Error: " + std::string(SDL_GetError()));
    return nullptr;
  }
  int width = surface->w;
  int height = surface->h;

  SDL_FreeSurface(surface);
  return DumbPtr<Texture>(new SDLTexture(texture, width, height));
}

Diamond::DumbPtr<Diamond::Texture>
Diamond::SDLRenderer2D::loadTextTexture(const std::string &text,
                                        const Font *font, const RGBA &color) {
  auto sdlfont = dynamic_cast<const SDLFont *>(font);
  if (sdlfont) {
    SDL_Color sdlcolor = {color.r, color.g, color.b, color.a};

    SDL_Surface *surface =
        TTF_RenderText_Solid(sdlfont->font, text.c_str(), sdlcolor);

    if (surface == NULL) {
      Log::log("Failed to load text " + text +
               ". SDL_ttf Error: " + std::string(TTF_GetError()));
      return nullptr;
    }

    SDL_Texture *texture = SDL_CreateTextureFromSurface(m_renderer, surface);
    if (texture == NULL) {
      Log::log("Failed to create texture for text " + text +
               ". SDL Error: " + std::string(SDL_GetError()));
      return nullptr;
    }
    int width = surface->w;
    int height = surface->h;

    SDL_FreeSurface(surface);
    // TODO: use memory pool!
    return DumbPtr<Texture>(new SDLTexture(texture, width, height));
  } else {
    Log::log("Given Font is not an SDLFont.");
  }
  return nullptr;
}

Diamond::DumbPtr<Diamond::RenderComponent2D>
Diamond::SDLRenderer2D::makeRenderComponent(const DTransform2 &transform,
                                            const Texture *texture,
                                            RenderLayer layer,
                                            const Vector2<tD_pos> &pivot) {
  // Make room for a new layer if necessary
  if ((int)layer > (int)m_render_objects.size() - 1) {
    m_render_objects.resize(layer + 1);
  }

  SDLrenderobj_id robj = m_render_objects[layer].emplace(
      transform, dynamic_cast<const SDLTexture *>(texture), pivot);

  return m_renderCompPool.make(*this, robj, texture, layer);
}

void Diamond::SDLRenderer2D::renderPoint(const Vector2<tD_pos> &coords,
                                         const RGBA &color) {
  m_render_points_queue.push_back({coords, color});
}

void Diamond::SDLRenderer2D::renderLine(const Vector2<tD_pos> &p1,
                                        const Vector2<tD_pos> &p2,
                                        const RGBA &color) {
  m_render_lines_queue.push_back({p1, p2, color});
}

Diamond::SDLrenderobj_id
Diamond::SDLRenderer2D::changeLayer(RenderLayer curLayer, SDLrenderobj_id robj,
                                    RenderLayer newLayer) {
  // Make room for a new layer if necessary
  if (newLayer + 1 > m_render_objects.size()) {
    m_render_objects.resize(newLayer + 1);
  }

  SDLrenderobj_id newID = m_render_objects[newLayer].insert(
      std::move(m_render_objects[curLayer][robj]));
  m_render_objects[curLayer].erase(robj);

  return newID;
}
<commit_msg>Added High DPI support<commit_after>/*
    Copyright 2015 Ahnaf Siddiqui

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "D_SDLRenderer2D.h"

#include "D_Log.h"
#include "D_SDLRenderComponent2D.h"
#include "D_SDLTexture.h"
#include "D_Transform2.h"
#include "SDL_image.h"
#include <iostream>

Diamond::SDLRenderer2D::SDLRenderer2D(const Config &config, bool &success)
    : m_window(nullptr), m_renderer(nullptr), m_bgColor({0, 0, 0, 100}),
      m_renderCompPool(config.max_gameobjects_estimate) {
  success = true;

  // Initialize SDL
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
    Log::log("SDL failed to initialize! SDL Error: " +
             std::string(SDL_GetError()));
    success = false;
  }

  // Create window
  if (success) {
    auto flags = SDL_WINDOW_ALLOW_HIGHDPI;
    if (config.fullscreen || config.window_width <= 0 || config.window_height <= 0) {
      flags = (SDL_WindowFlags)(flags | SDL_WINDOW_FULLSCREEN_DESKTOP);
    }
    m_window = SDL_CreateWindow(
        config.game_name.c_str(), SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, config.window_width, config.window_height,
        flags);
    if (m_window == nullptr) {
      Log::log("SDL failed to create window! SDL Error: " +
               std::string(SDL_GetError()));
      success = false;
    }
  }

  // Create renderer
  if (success) {
    m_renderer = SDL_CreateRenderer(
        m_window, -1,
        SDL_RENDERER_ACCELERATED |
            (config.vsync ? SDL_RENDERER_PRESENTVSYNC : 0x00000000));
    if (m_renderer == nullptr) {
      Log::log("SDL failed to create renderer! SDL Error: " +
               std::string(SDL_GetError()));
      success = false;
    }
  }

  // Set background color
  m_bgColor = config.bg_color;

  // Initialize image loading
  int img_flags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF;
  if (IMG_Init(img_flags) != img_flags) {
    Log::log("SDL_image failed to initialize! SDL_image Error: " +
             std::string(IMG_GetError()));
    // success = false; // TODO: what's wrong with SDL Image init on Android?
  }

  // Initialize text rendering
  if (TTF_Init() < 0) {
    Log::log("SDL_ttf failed to initialize! SDL_ttf Error: " +
             std::string(TTF_GetError()));
    success = false;
  }

  if (success && config.optimize_render_layers) {
    m_render_objects.resize(config.num_render_layers_estimate);

    for (int i = 0; i < config.num_render_layers_estimate; ++i) {
      m_render_objects[i].data().reserve(config.max_gameobjects_estimate);
    }
  }
}

Diamond::SDLRenderer2D::~SDLRenderer2D() {
  SDL_DestroyRenderer(m_renderer);
  SDL_DestroyWindow(m_window);

  TTF_Quit();
  IMG_Quit();
  SDL_Quit();
}

void Diamond::SDLRenderer2D::renderAll() {
  // Render background
  SDL_SetRenderDrawColor(m_renderer, m_bgColor.r, m_bgColor.g, m_bgColor.b,
                         m_bgColor.a);
  SDL_RenderClear(m_renderer);

  // Render sprites
  for (auto l = m_render_objects.begin(); l != m_render_objects.end(); ++l) {
    for (auto i = l->begin(); i != l->end(); ++i) {
      const auto &transform = i->getTransform();

      auto pivot = i->pivot();
      auto &clip = i->clip();

      pivot.x *= transform.scale.x;
      pivot.y *= transform.scale.y;

      SDL_Rect render_rect = {
          (int)(transform.position.x - pivot.x), // render position x
          (int)(transform.position.y - pivot.y), // render position y
          (int)(clip.w * transform.scale.x),     // render width
          (int)(clip.h * transform.scale.y)      // render height
      };

      // Set transparency
      const auto &color = i->color();
      SDL_SetTextureColorMod(i->texture(), color.r, color.g, color.b);
      SDL_SetTextureAlphaMod(i->texture(), i->alpha());

      SDL_RenderCopyEx(
          m_renderer,         // The SDL backend renderer for this SDL instance.
          i->texture(),       // sprite
          &clip,              // source rect
          &render_rect,       // destination rect
          transform.rotation, // rotation for destination rect in degrees
          &pivot,             // rotation pivot location in local space
          i->getFlip()        // current flip status
          );

      // Reset the texture's transparency before the next render
      SDL_SetTextureColorMod(i->texture(), 255, 255, 255);
      SDL_SetTextureAlphaMod(i->texture(), 255);
    }
  }

  // Render points
  for (SDLRenderablePoint point : m_render_points_queue) {
    SDL_SetRenderDrawColor(m_renderer, point.color.r, point.color.g,
                           point.color.b, point.color.a);

    SDL_RenderDrawPoint(m_renderer, point.coords.x, point.coords.y);
  }

  m_render_points_queue.clear();

  // Render lines
  for (SDLRenderableLine line : m_render_lines_queue) {
    SDL_SetRenderDrawColor(m_renderer, line.color.r, line.color.g, line.color.b,
                           line.color.a);

    SDL_RenderDrawLine(m_renderer, line.p1.x, line.p1.y, line.p2.x, line.p2.y);
  }

  m_render_lines_queue.clear();

  // Update screen
  SDL_RenderPresent(m_renderer);
}

Diamond::Vector2<int> Diamond::SDLRenderer2D::getScreenResolution() const {
  SDL_DisplayMode mode;
  SDL_GetCurrentDisplayMode(0, &mode);
  return Vector2<int>(mode.w, mode.h);
}

Diamond::Vector2<int> Diamond::SDLRenderer2D::getResolution() const {
  Vector2<int> r;
  SDL_GL_GetDrawableSize(m_window, &(r.x), &(r.y));
  return r;
}

int Diamond::SDLRenderer2D::getRefreshRate() const {
  SDL_DisplayMode mode;
  SDL_GetCurrentDisplayMode(0, &mode);
  return mode.refresh_rate;
}

Diamond::DumbPtr<Diamond::Font>
Diamond::SDLRenderer2D::loadFont(const std::string &fontPath, int ptsize) {
  TTF_Font *font = TTF_OpenFont(fontPath.c_str(), ptsize);
  if (!font) {
    Log::log("Failed to load font " + fontPath +
             "! SDL_ttf Error: " + std::string(TTF_GetError()));
    return nullptr;
  }
  return DumbPtr<Font>(new SDLFont(font));
}

Diamond::DumbPtr<Diamond::Texture>
Diamond::SDLRenderer2D::loadTexture(std::string path) {
  SDL_Surface *surface = IMG_Load(path.c_str());
  if (surface == NULL) {
    Log::log("Failed to load image " + path +
             "! SDL_image Error: " + std::string(IMG_GetError()));
    return nullptr;
  }

  SDL_Texture *texture = SDL_CreateTextureFromSurface(m_renderer, surface);
  if (texture == NULL) {
    Log::log("Failed to create texture from " + path +
             "! SDL Error: " + std::string(SDL_GetError()));
    return nullptr;
  }
  int width = surface->w;
  int height = surface->h;

  SDL_FreeSurface(surface);
  return DumbPtr<Texture>(new SDLTexture(texture, width, height));
}

Diamond::DumbPtr<Diamond::Texture>
Diamond::SDLRenderer2D::loadTextTexture(const std::string &text,
                                        const Font *font, const RGBA &color) {
  auto sdlfont = dynamic_cast<const SDLFont *>(font);
  if (sdlfont) {
    SDL_Color sdlcolor = {color.r, color.g, color.b, color.a};

    SDL_Surface *surface =
        TTF_RenderText_Solid(sdlfont->font, text.c_str(), sdlcolor);

    if (surface == NULL) {
      Log::log("Failed to load text " + text +
               ". SDL_ttf Error: " + std::string(TTF_GetError()));
      return nullptr;
    }

    SDL_Texture *texture = SDL_CreateTextureFromSurface(m_renderer, surface);
    if (texture == NULL) {
      Log::log("Failed to create texture for text " + text +
               ". SDL Error: " + std::string(SDL_GetError()));
      return nullptr;
    }
    int width = surface->w;
    int height = surface->h;

    SDL_FreeSurface(surface);
    // TODO: use memory pool!
    return DumbPtr<Texture>(new SDLTexture(texture, width, height));
  } else {
    Log::log("Given Font is not an SDLFont.");
  }
  return nullptr;
}

Diamond::DumbPtr<Diamond::RenderComponent2D>
Diamond::SDLRenderer2D::makeRenderComponent(const DTransform2 &transform,
                                            const Texture *texture,
                                            RenderLayer layer,
                                            const Vector2<tD_pos> &pivot) {
  // Make room for a new layer if necessary
  if ((int)layer > (int)m_render_objects.size() - 1) {
    m_render_objects.resize(layer + 1);
  }

  SDLrenderobj_id robj = m_render_objects[layer].emplace(
      transform, dynamic_cast<const SDLTexture *>(texture), pivot);

  return m_renderCompPool.make(*this, robj, texture, layer);
}

void Diamond::SDLRenderer2D::renderPoint(const Vector2<tD_pos> &coords,
                                         const RGBA &color) {
  m_render_points_queue.push_back({coords, color});
}

void Diamond::SDLRenderer2D::renderLine(const Vector2<tD_pos> &p1,
                                        const Vector2<tD_pos> &p2,
                                        const RGBA &color) {
  m_render_lines_queue.push_back({p1, p2, color});
}

Diamond::SDLrenderobj_id
Diamond::SDLRenderer2D::changeLayer(RenderLayer curLayer, SDLrenderobj_id robj,
                                    RenderLayer newLayer) {
  // Make room for a new layer if necessary
  if (newLayer + 1 > m_render_objects.size()) {
    m_render_objects.resize(newLayer + 1);
  }

  SDLrenderobj_id newID = m_render_objects[newLayer].insert(
      std::move(m_render_objects[curLayer][robj]));
  m_render_objects[curLayer].erase(robj);

  return newID;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2018, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "filesystemwatcher.h"
#include "abstractproject.h"
#include "abstractresourceitem.h"
#include "abstractresourcelist.h"
#include "models/common/imagecache.h"

#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QLabel>
#include <QMessageBox>

using namespace UnTech::GuiQt;

FilesystemWatcher::FilesystemWatcher(AbstractProject* project)
    : QObject(project)
    , _project(project)
    , _watcher(new QFileSystemWatcher(this))
    , _projectWatcher(new QFileSystemWatcher(this))
    , _filesChangedDialogActive(false)
    , _filenameToItems()
    , _itemToFilenames()
{
    Q_ASSERT(project);

    watchProjectFile();

    connect(_watcher, &QFileSystemWatcher::fileChanged,
            this, &FilesystemWatcher::onFileChanged);

    connect(_projectWatcher, &QFileSystemWatcher::fileChanged,
            this, &FilesystemWatcher::onProjectFileChanged);

    connect(_project, &AbstractProject::filenameChanged,
            this, &FilesystemWatcher::watchProjectFile);

    connect(_project, &AbstractProject::aboutToSaveProject,
            this, &FilesystemWatcher::onAboutToSaveProject);

    connect(_project, &AbstractProject::resourceItemCreated,
            this, &FilesystemWatcher::onResourceItemCreated);

    connect(_project, &AbstractProject::selectedResourceChanged,
            this, &FilesystemWatcher::onSelectedResourceChanged);

    connect(_project, &AbstractProject::resourceItemAboutToBeRemoved,
            this, &FilesystemWatcher::removeResourceItem);
}

void FilesystemWatcher::watchProjectFile()
{
    QString fn = _project->filename();
    if (fn.isEmpty() == false) {
        fn = QDir::fromNativeSeparators(fn);
    }

    QStringList toRemove = _projectWatcher->files();
    toRemove << _projectWatcher->directories();

    if (toRemove.size() == 1 && toRemove.first() == fn) {
        // already watching project file
        return;
    }

    if (toRemove.isEmpty() == false) {
        _projectWatcher->removePaths(toRemove);
    }

    if (fn.isEmpty() == false && QFile::exists(fn)) {
        _projectWatcher->addPath(_project->filename());
    }
}

void FilesystemWatcher::onAboutToSaveProject()
{
    _filesSavedLocally.append(_project->filename());
}

void FilesystemWatcher::onProjectFileChanged(const QString& path)
{
    QString nativePath = QDir::toNativeSeparators(path);

    if (_filesSavedLocally.contains(nativePath)) {
        // Do not process items were saved by the editor
        _filesSavedLocally.removeAll(nativePath);

        // If the path was replaced we need to add it to the watcher again.
        watchProjectFile();
        return;
    }

    _project->undoStack()->resetClean();
    for (AbstractResourceList* rl : _project->resourceLists()) {
        for (AbstractResourceItem* item : rl->items()) {
            if (auto* inItem = qobject_cast<AbstractInternalResourceItem*>(item)) {
                inItem->undoStack()->resetClean();
            }
        }
    }

    QMessageBox::warning(
        nullptr, tr("Project File Changed"),
        tr("The project file \"%1\" has been changed on disk.\n"
           "Please save or discard changes manually.")
            .arg(QFileInfo(path).fileName()));

    watchProjectFile();
}

void FilesystemWatcher::onResourceItemCreated(AbstractResourceItem* item)
{
    updateWatcherAndMaps(item);

    connect(item, &AbstractResourceItem::externalFilesChanged,
            this, &FilesystemWatcher::onResourceItemExternalFilesChanged);

    if (auto* exItem = qobject_cast<AbstractExternalResourceItem*>(item)) {
        connect(exItem, &AbstractExternalResourceItem::aboutToSaveResource,
                this, &FilesystemWatcher::onAboutToSaveResource);
    }
}

void FilesystemWatcher::onSelectedResourceChanged()
{
    // Reload the watcher when the selected item is changed.
    // Just in case a file that did not exist is now existing.

    if (auto* item = _project->selectedResource()) {
        updateWatcherAndMaps(item);
    }
}

void FilesystemWatcher::onResourceItemExternalFilesChanged()
{
    auto* item = qobject_cast<AbstractResourceItem*>(sender());
    if (item) {
        updateWatcherAndMaps(item);
    }
}

static QStringList resourceNativeFilenames(const AbstractResourceItem* item)
{
    QStringList nativeFilenames = item->externalFiles();

    if (auto* exItem = qobject_cast<const AbstractExternalResourceItem*>(item)) {
        nativeFilenames << exItem->filename();
    }

    nativeFilenames.removeAll(QString());

    for (QString& fn : nativeFilenames) {
        fn = QDir::toNativeSeparators(QFileInfo(fn).absoluteFilePath());
    }

    return nativeFilenames;
}

void FilesystemWatcher::updateWatcherAndMaps(AbstractResourceItem* item)
{
    Q_ASSERT(item);

    const QStringList nativeFilenames = resourceNativeFilenames(item);
    const QStringList watchedFiles = _watcher->files();
    const QStringList previousFilenames = _itemToFilenames.value(item);

    bool emitModified = previousFilenames != nativeFilenames;

    {
        // Check the watched/existing status of every filename.
        // It may not have existed in the past, but it could exist now.

        QStringList toWatch;
        toWatch.reserve(nativeFilenames.size());

        for (const QString& nativePath : nativeFilenames) {
            QString path = QDir::fromNativeSeparators(nativePath);

            bool fileUnwatched = watchedFiles.contains(path) == false;
            bool fileExists = QFile::exists(nativePath);

            if (fileUnwatched && fileExists) {
                toWatch << path;

                emitModified = true;
            }
            if (fileUnwatched || !fileExists) {
                ImageCache::invalidateFilename(nativePath.toStdString());
            }
        }

        if (toWatch.isEmpty() == false) {
            // This is more efficient then adding paths one at a time
            _watcher->addPaths(toWatch);
        }
    }

    QStringList toAdd = nativeFilenames;

    for (const QString& prevFilename : previousFilenames) {
        int i = toAdd.indexOf(prevFilename);
        if (i >= 0) {
            toAdd.removeAt(i);
        }
        else {
            removeFilenameItemMapping(prevFilename, item);
        }
    }

    for (const QString& filename : toAdd) {
        auto it = _filenameToItems.find(filename);
        if (it == _filenameToItems.end()) {
            it = _filenameToItems.insert(filename, {});
        }
        if (it->contains(item) == false) {
            it->append(item);
        }
    }

    if (nativeFilenames.isEmpty() == false) {
        _itemToFilenames.insert(item, nativeFilenames);
    }
    else {
        _itemToFilenames.remove(item);
    }

    if (emitModified) {
        emit item->externalFilesModified();

        item->markUnchecked();
    }
}

void FilesystemWatcher::removeResourceItem(AbstractResourceItem* item)
{
    Q_ASSERT(item);

    const QStringList filenames = _itemToFilenames.value(item);
    for (const QString& fn : filenames) {
        removeFilenameItemMapping(fn, item);
    }

    _itemToFilenames.remove(item);
}

void FilesystemWatcher::removeFilenameItemMapping(const QString& filename, AbstractResourceItem* item)
{
    auto it = _filenameToItems.find(filename);
    if (it != _filenameToItems.end()) {
        it->removeAll(item);
        if (it->isEmpty()) {
            _watcher->removePath(filename);

            _filenameToItems.remove(filename);
        }
    }
}

void FilesystemWatcher::onAboutToSaveResource()
{
    auto* item = qobject_cast<AbstractExternalResourceItem*>(sender());
    if (item) {
        _filesSavedLocally.append(item->filename());
    }
}

void FilesystemWatcher::onFileChanged(const QString& path)
{
    // If the path was replaced (ie, file copy or atomic write) then the
    // watcher will automatically remove the path and we need to add it back
    // again.
    if (_watcher->files().contains(path) == false) {
        if (QFile::exists(path)) {
            _watcher->addPath(path);
        }
    }

    QString nativePath = QDir::toNativeSeparators(path);

    ImageCache::invalidateFilename(nativePath.toStdString());

    if (_filesSavedLocally.contains(nativePath)) {
        // Do not process items were saved by the editor
        _filesSavedLocally.removeAll(nativePath);
        return;
    }

    auto it = _filenameToItems.find(nativePath);
    if (it != _filenameToItems.end()) {
        const auto& items = *it;

        for (AbstractResourceItem* item : items) {
            if (auto* exItem = qobject_cast<AbstractExternalResourceItem*>(item)) {
                if (nativePath == exItem->filename()) {
                    resourceChangedOnDisk(exItem);
                    continue;
                }
            }

            emit item->externalFilesModified();

            item->markUnchecked();
        }
    }
    else {
        qWarning() << nativePath << "is not linked to a ResourceItem";
    }
}

void FilesystemWatcher::resourceChangedOnDisk(AbstractExternalResourceItem* item)
{
    if (_changedResources.contains(item) == false) {
        _changedResources.append(item);
    }
    if (_filesChangedDialogActive == false) {
        showFilesChangedDialog();
    }
}

void FilesystemWatcher::showFilesChangedDialog()
{
    Q_ASSERT(_filesChangedDialogActive == false);
    _filesChangedDialogActive = true;

    QMessageBox dialog;

    dialog.setWindowTitle(tr("Changed Files"));
    dialog.addButton(QMessageBox::Yes);
    dialog.addButton(QMessageBox::No);
    dialog.addButton(QMessageBox::NoToAll);
    dialog.setDefaultButton(QMessageBox::No);

    {
        // Set size of dialog so the buttons are always in the same place.

        // QMessageDialog setSize methods do not work,
        // however setting the size of the label does.

        QSize labelSize(dialog.fontMetrics().width('m') * 50,
                        dialog.fontMetrics().height() * 5);

        for (QLabel* l : dialog.findChildren<QLabel*>()) {
            l->setFixedSize(labelSize);
        }
    }

    while (!_changedResources.empty()) {
        QPointer<AbstractExternalResourceItem> item = _changedResources.first();

        if (item) {
            dialog.setText(tr("The file \"%1\" has been changed on disk.\n"
                              "Do you want to reload it?\n\n"
                              "You will not be able to undo this action.")
                               .arg(item->relativeFilePath()));

            dialog.exec();

            switch (dialog.result()) {
            case QMessageBox::Yes:
                if (item) {
                    auto* newItem = item->resourceList()->revertResource(item);
                    newItem->project()->setSelectedResource(newItem);
                }
                _changedResources.removeFirst();
                break;

            case QMessageBox::No:
                if (item) {
                    item->undoStack()->resetClean();
                }
                _changedResources.removeFirst();
                break;

            case QMessageBox::NoToAll:
                for (auto& i : _changedResources) {
                    if (i) {
                        i->undoStack()->resetClean();
                    }
                }
                _changedResources.clear();
                break;
            }
        }
    }

    _filesChangedDialogActive = false;
}
<commit_msg>Update onFileChanged to check the path status at the end of routine<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2018, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "filesystemwatcher.h"
#include "abstractproject.h"
#include "abstractresourceitem.h"
#include "abstractresourcelist.h"
#include "models/common/imagecache.h"

#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QLabel>
#include <QMessageBox>

using namespace UnTech::GuiQt;

FilesystemWatcher::FilesystemWatcher(AbstractProject* project)
    : QObject(project)
    , _project(project)
    , _watcher(new QFileSystemWatcher(this))
    , _projectWatcher(new QFileSystemWatcher(this))
    , _filesChangedDialogActive(false)
    , _filenameToItems()
    , _itemToFilenames()
{
    Q_ASSERT(project);

    watchProjectFile();

    connect(_watcher, &QFileSystemWatcher::fileChanged,
            this, &FilesystemWatcher::onFileChanged);

    connect(_projectWatcher, &QFileSystemWatcher::fileChanged,
            this, &FilesystemWatcher::onProjectFileChanged);

    connect(_project, &AbstractProject::filenameChanged,
            this, &FilesystemWatcher::watchProjectFile);

    connect(_project, &AbstractProject::aboutToSaveProject,
            this, &FilesystemWatcher::onAboutToSaveProject);

    connect(_project, &AbstractProject::resourceItemCreated,
            this, &FilesystemWatcher::onResourceItemCreated);

    connect(_project, &AbstractProject::selectedResourceChanged,
            this, &FilesystemWatcher::onSelectedResourceChanged);

    connect(_project, &AbstractProject::resourceItemAboutToBeRemoved,
            this, &FilesystemWatcher::removeResourceItem);
}

void FilesystemWatcher::watchProjectFile()
{
    QString fn = _project->filename();
    if (fn.isEmpty() == false) {
        fn = QDir::fromNativeSeparators(fn);
    }

    QStringList toRemove = _projectWatcher->files();
    toRemove << _projectWatcher->directories();

    if (toRemove.size() == 1 && toRemove.first() == fn) {
        // already watching project file
        return;
    }

    if (toRemove.isEmpty() == false) {
        _projectWatcher->removePaths(toRemove);
    }

    if (fn.isEmpty() == false && QFile::exists(fn)) {
        _projectWatcher->addPath(_project->filename());
    }
}

void FilesystemWatcher::onAboutToSaveProject()
{
    _filesSavedLocally.append(_project->filename());
}

void FilesystemWatcher::onProjectFileChanged(const QString& path)
{
    QString nativePath = QDir::toNativeSeparators(path);

    if (_filesSavedLocally.contains(nativePath)) {
        // Do not process items were saved by the editor
        _filesSavedLocally.removeAll(nativePath);

        // If the path was replaced we need to add it to the watcher again.
        watchProjectFile();
        return;
    }

    _project->undoStack()->resetClean();
    for (AbstractResourceList* rl : _project->resourceLists()) {
        for (AbstractResourceItem* item : rl->items()) {
            if (auto* inItem = qobject_cast<AbstractInternalResourceItem*>(item)) {
                inItem->undoStack()->resetClean();
            }
        }
    }

    QMessageBox::warning(
        nullptr, tr("Project File Changed"),
        tr("The project file \"%1\" has been changed on disk.\n"
           "Please save or discard changes manually.")
            .arg(QFileInfo(path).fileName()));

    watchProjectFile();
}

void FilesystemWatcher::onResourceItemCreated(AbstractResourceItem* item)
{
    updateWatcherAndMaps(item);

    connect(item, &AbstractResourceItem::externalFilesChanged,
            this, &FilesystemWatcher::onResourceItemExternalFilesChanged);

    if (auto* exItem = qobject_cast<AbstractExternalResourceItem*>(item)) {
        connect(exItem, &AbstractExternalResourceItem::aboutToSaveResource,
                this, &FilesystemWatcher::onAboutToSaveResource);
    }
}

void FilesystemWatcher::onSelectedResourceChanged()
{
    // Reload the watcher when the selected item is changed.
    // Just in case a file that did not exist is now existing.

    if (auto* item = _project->selectedResource()) {
        updateWatcherAndMaps(item);
    }
}

void FilesystemWatcher::onResourceItemExternalFilesChanged()
{
    auto* item = qobject_cast<AbstractResourceItem*>(sender());
    if (item) {
        updateWatcherAndMaps(item);
    }
}

static QStringList resourceNativeFilenames(const AbstractResourceItem* item)
{
    QStringList nativeFilenames = item->externalFiles();

    if (auto* exItem = qobject_cast<const AbstractExternalResourceItem*>(item)) {
        nativeFilenames << exItem->filename();
    }

    nativeFilenames.removeAll(QString());

    for (QString& fn : nativeFilenames) {
        fn = QDir::toNativeSeparators(QFileInfo(fn).absoluteFilePath());
    }

    return nativeFilenames;
}

void FilesystemWatcher::updateWatcherAndMaps(AbstractResourceItem* item)
{
    Q_ASSERT(item);

    const QStringList nativeFilenames = resourceNativeFilenames(item);
    const QStringList watchedFiles = _watcher->files();
    const QStringList previousFilenames = _itemToFilenames.value(item);

    bool emitModified = previousFilenames != nativeFilenames;

    {
        // Check the watched/existing status of every filename.
        // It may not have existed in the past, but it could exist now.

        QStringList toWatch;
        toWatch.reserve(nativeFilenames.size());

        for (const QString& nativePath : nativeFilenames) {
            QString path = QDir::fromNativeSeparators(nativePath);

            bool fileUnwatched = watchedFiles.contains(path) == false;
            bool fileExists = QFile::exists(nativePath);

            if (fileUnwatched && fileExists) {
                toWatch << path;

                emitModified = true;
            }
            if (fileUnwatched || !fileExists) {
                ImageCache::invalidateFilename(nativePath.toStdString());
            }
        }

        if (toWatch.isEmpty() == false) {
            // This is more efficient then adding paths one at a time
            _watcher->addPaths(toWatch);
        }
    }

    QStringList toAdd = nativeFilenames;

    for (const QString& prevFilename : previousFilenames) {
        int i = toAdd.indexOf(prevFilename);
        if (i >= 0) {
            toAdd.removeAt(i);
        }
        else {
            removeFilenameItemMapping(prevFilename, item);
        }
    }

    for (const QString& filename : toAdd) {
        auto it = _filenameToItems.find(filename);
        if (it == _filenameToItems.end()) {
            it = _filenameToItems.insert(filename, {});
        }
        if (it->contains(item) == false) {
            it->append(item);
        }
    }

    if (nativeFilenames.isEmpty() == false) {
        _itemToFilenames.insert(item, nativeFilenames);
    }
    else {
        _itemToFilenames.remove(item);
    }

    if (emitModified) {
        emit item->externalFilesModified();

        item->markUnchecked();
    }
}

void FilesystemWatcher::removeResourceItem(AbstractResourceItem* item)
{
    Q_ASSERT(item);

    const QStringList filenames = _itemToFilenames.value(item);
    for (const QString& fn : filenames) {
        removeFilenameItemMapping(fn, item);
    }

    _itemToFilenames.remove(item);
}

void FilesystemWatcher::removeFilenameItemMapping(const QString& filename, AbstractResourceItem* item)
{
    auto it = _filenameToItems.find(filename);
    if (it != _filenameToItems.end()) {
        it->removeAll(item);
        if (it->isEmpty()) {
            _watcher->removePath(filename);

            _filenameToItems.remove(filename);
        }
    }
}

void FilesystemWatcher::onAboutToSaveResource()
{
    auto* item = qobject_cast<AbstractExternalResourceItem*>(sender());
    if (item) {
        _filesSavedLocally.append(item->filename());
    }
}

void FilesystemWatcher::onFileChanged(const QString& path)
{
    auto watchPathAgain = [&]() {
        // If the path was replaced (ie, file copy or atomic write) then the
        // watcher will automatically remove the path and we need to add it back
        // again.
        if (_watcher->files().contains(path) == false) {
            if (QFile::exists(path)) {
                _watcher->addPath(path);
            }
        }
    };

    QString nativePath = QDir::toNativeSeparators(path);

    ImageCache::invalidateFilename(nativePath.toStdString());

    if (_filesSavedLocally.contains(nativePath)) {
        // Do not process items were saved by the editor
        _filesSavedLocally.removeAll(nativePath);

        watchPathAgain();
        return;
    }

    auto it = _filenameToItems.find(nativePath);
    if (it != _filenameToItems.end()) {
        const auto& items = *it;

        for (AbstractResourceItem* item : items) {
            if (auto* exItem = qobject_cast<AbstractExternalResourceItem*>(item)) {
                if (nativePath == exItem->filename()) {
                    resourceChangedOnDisk(exItem);
                    continue;
                }
            }

            emit item->externalFilesModified();

            item->markUnchecked();
        }
    }
    else {
        qWarning() << nativePath << "is not linked to a ResourceItem";
    }

    watchPathAgain();
}

void FilesystemWatcher::resourceChangedOnDisk(AbstractExternalResourceItem* item)
{
    if (_changedResources.contains(item) == false) {
        _changedResources.append(item);
    }
    if (_filesChangedDialogActive == false) {
        showFilesChangedDialog();
    }
}

void FilesystemWatcher::showFilesChangedDialog()
{
    Q_ASSERT(_filesChangedDialogActive == false);
    _filesChangedDialogActive = true;

    QMessageBox dialog;

    dialog.setWindowTitle(tr("Changed Files"));
    dialog.addButton(QMessageBox::Yes);
    dialog.addButton(QMessageBox::No);
    dialog.addButton(QMessageBox::NoToAll);
    dialog.setDefaultButton(QMessageBox::No);

    {
        // Set size of dialog so the buttons are always in the same place.

        // QMessageDialog setSize methods do not work,
        // however setting the size of the label does.

        QSize labelSize(dialog.fontMetrics().width('m') * 50,
                        dialog.fontMetrics().height() * 5);

        for (QLabel* l : dialog.findChildren<QLabel*>()) {
            l->setFixedSize(labelSize);
        }
    }

    while (!_changedResources.empty()) {
        QPointer<AbstractExternalResourceItem> item = _changedResources.first();

        if (item) {
            dialog.setText(tr("The file \"%1\" has been changed on disk.\n"
                              "Do you want to reload it?\n\n"
                              "You will not be able to undo this action.")
                               .arg(item->relativeFilePath()));

            dialog.exec();

            switch (dialog.result()) {
            case QMessageBox::Yes:
                if (item) {
                    auto* newItem = item->resourceList()->revertResource(item);
                    newItem->project()->setSelectedResource(newItem);
                }
                _changedResources.removeFirst();
                break;

            case QMessageBox::No:
                if (item) {
                    item->undoStack()->resetClean();
                }
                _changedResources.removeFirst();
                break;

            case QMessageBox::NoToAll:
                for (auto& i : _changedResources) {
                    if (i) {
                        i->undoStack()->resetClean();
                    }
                }
                _changedResources.clear();
                break;
            }
        }
    }

    _filesChangedDialogActive = false;
}
<|endoftext|>


<commit_before>#include <Halide.h>
#include <sys/time.h>

using namespace Halide;

double currentTime() {
    timeval t;
    gettimeofday(&t, NULL);
    return t.tv_sec * 1000.0 + t.tv_usec / 1000.0f;
}

int main(int argc, char **argv) {

    Func f, g, h; Var x, y;

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

    h.root();
    g.root();

    if (use_gpu()) {
        f.cudaTile(x, y, 16, 16);
        g.cudaTile(x, 128);
        h.cudaTile(x, 128);
    }

    Image<int> out = f.realize(32, 32);

    for (int y = 0; y < 32; y++) {
        for (int x = 0; x < 32; x++) {
            if (out(x, y) != x*4 + y) {
                printf("out(%d, %d) = %d instead of %d\n", x, y, out(x, y), x*4+y);
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Clear spurious timing code from bounds_interence<commit_after>#include <Halide.h>
using namespace Halide;

int main(int argc, char **argv) {

    Func f, g, h; Var x, y;

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

    h.root();
    g.root();

    if (use_gpu()) {
        f.cudaTile(x, y, 16, 16);
        g.cudaTile(x, 128);
        h.cudaTile(x, 128);
    }

    Image<int> out = f.realize(32, 32);

    for (int y = 0; y < 32; y++) {
        for (int x = 0; x < 32; x++) {
            if (out(x, y) != x*4 + y) {
                printf("out(%d, %d) = %d instead of %d\n", x, y, out(x, y), x*4+y);
                return -1;
            }
        }
    }

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


<commit_before>/*
 * XMLSaveHandler.cpp
 *
 *  Created on: 29.05.2017
 *      Author: Alexander
 */

#include "persistence/xml/XMLSaveHandler.hpp"

#ifdef NDEBUG
#define MSG_DEBUG(a) /**/
#else
#define MSG_DEBUG(a) std::cout << "| DEBUG    | " << a << std::endl
#endif
#define MSG_WARNING(a) std::cout << "| WARNING  | "<< a << std::endl
#define MSG_ERROR(a) std::cout << "| ERROR    | " << a << std::endl
#define MSG_FLF __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << "() "

#include <iostream>
#include <sstream> // used for addReferences()

#include "boost/algorithm/string.hpp" // used for string splitting
#include "ecore/EObject.hpp"
#include "persistence/base/HandlerHelper.hpp"

#include "xerces/XStr.hpp"
#include "xerces/WStr.hpp"
#include "xercesc/dom/DOMException.hpp"
#include "xercesc/util/OutOfMemoryException.hpp"

using namespace persistence::xml;

XMLSaveHandler::XMLSaveHandler ()
{
	m_doc = nullptr;
	m_currentElement = nullptr;
}

XMLSaveHandler::~XMLSaveHandler ()
{
	if ( m_doc )
	{
		m_doc->release();
	}
}

/**/
DOMDocument *XMLSaveHandler::getDOMDocument ()
{
	return m_doc;
}

bool XMLSaveHandler::createRootNode ( const std::string& name, const std::string& ns_uri )
{
	return this->createRootNode( name, ns_uri, nullptr );
}

bool XMLSaveHandler::createRootNode ( const std::string& prefix, const std::string& name, const std::string& ns_uri )
{
	return this->createRootNode( prefix, name, ns_uri, nullptr );
}

bool XMLSaveHandler::createRootNode ( const std::string& prefix, const std::string& name, const std::string& ns_uri, DOMDocumentType *doctype )
{
	m_rootPrefix = prefix;
	return this->createRootNode( prefix + ":" + name, ns_uri, doctype );
}

bool XMLSaveHandler::createRootNode ( const std::string& name, const std::string& ns_uri, DOMDocumentType *doctype )
{
	DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation( X( "Core" ) );

	if ( impl != NULL )
	{
		try
		{
			m_doc = impl->createDocument( (ns_uri.empty()) ? 0 : X( ns_uri ), // root element namespace URI.
			X( name ),         					// root element name
			doctype ); 	                		// document type object (DTD).

			m_currentElement = m_doc->getDocumentElement(); // get root element
			m_currentElement->setAttribute(X("xmi:version"), X("2.0"));
			m_currentElement->setAttribute(X("xmlns:xmi"), X("http://www.omg.org/XMI"));
			m_currentElement->setAttribute(X("xmlns:xsi"), X("http://www.w3.org/2001/XMLSchema-instance"));
		}
		catch ( const OutOfMemoryException& )
		{
			MSG_ERROR( MSG_FLF << "OutOfMemoryException" );
			//errorCode = 5;
			return false;
		}
		catch ( const DOMException& e )
		{
			MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
			//errorCode = 2;
			return false;
		}
		catch ( ... )
		{
			MSG_ERROR( MSG_FLF <<"An error occurred creating the document" );
			//errorCode = 3;
			return false;
		}
	}  // (impl != NULL)
	else
	{
		MSG_ERROR( MSG_FLF <<"Requested implementation is not supported" );
		//errorCode = 4;
		return false;
	}

	return true;
}

bool XMLSaveHandler::createAndAddElement ( const std::string& name )
{
	if ( m_doc == nullptr )
	{
		MSG_ERROR( MSG_FLF <<"No root-Element created first" );
		return false;
	}
	else
	{
		addChild( m_currentElement, m_doc->createElement( X( name ) ) );

		return true;
	}
}

void XMLSaveHandler::addChild ( DOMElement* parent_elem, DOMElement* child_elem )
{
	// Add child to parent Element, and set child as current Element.
	m_currentElement = (DOMElement *) parent_elem->appendChild( child_elem );
}

void XMLSaveHandler::addAttribute ( const std::string& name, const std::string& value )
{
	try
	{
		m_currentElement->setAttribute( X( name ), X( value ) );
	}
	catch ( const DOMException& e )
	{
		MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
	}
	catch ( std::exception& e )
	{
		MSG_ERROR( MSG_FLF << "Exception code is:  " << e.what() );
	}
}

void XMLSaveHandler::addReferences ( const std::string &name, std::shared_ptr<ecore::EObject> object )
{
	if (object == nullptr)
	{
		std::cerr << "XMLSaveHandler::addReferences called with object == nullptr" << std::endl;
		return;
	}
	try
	{
		std::string ref = "";
		auto iter = m_refToObject_map.find(object);
		if (iter != m_refToObject_map.end())
		{
			ref = iter->second;
		}
		else
		{
			ref = persistence::base::HandlerHelper::extractReference( object, m_rootObject, m_rootPrefix );
		}

		std::stringstream ss;
		std::string tmpStr = W( m_currentElement->getAttribute(X( name )) );

		if ( !tmpStr.empty() )
		{
			ss << tmpStr << " ";
		}
		ss << ref;

		addAttribute( name, ss.str() );
	}
	catch ( const DOMException& e )
	{
		MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
	}
	catch ( std::exception& e )
	{
		MSG_ERROR( MSG_FLF << "Exception code is:  " << e.what() );
	}
}

void XMLSaveHandler::release ()
{
	if ( m_currentElement == nullptr )
	{
		MSG_ERROR( MSG_FLF << "Current DOMElement m_currentElement is nullptr" );
	}
	else
	{
		// set m_currentElement's parent node as new m_currentElement (decrease depth)
		m_currentElement = (DOMElement*) m_currentElement->getParentNode();
	}
}

void XMLSaveHandler::addTypeReference(const std::string& href, const std::string& xmitype)
{
	createAndAddElement("type");
	addAttribute("href", href);
	addAttribute("xmi:type", xmitype);
	release();
}

void XMLSaveHandler::addAttributeAsNode(const std::string& name, const std::string& value)
{
	createAndAddElement(name);
	m_currentElement->setTextContent(X(value));
	release();
}
<commit_msg>[persistence] save root id<commit_after>/*
 * XMLSaveHandler.cpp
 *
 *  Created on: 29.05.2017
 *      Author: Alexander
 */

#include "persistence/xml/XMLSaveHandler.hpp"

#ifdef NDEBUG
#define MSG_DEBUG(a) /**/
#else
#define MSG_DEBUG(a) std::cout << "| DEBUG    | " << a << std::endl
#endif
#define MSG_WARNING(a) std::cout << "| WARNING  | "<< a << std::endl
#define MSG_ERROR(a) std::cout << "| ERROR    | " << a << std::endl
#define MSG_FLF __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << "() "

#include <iostream>
#include <sstream> // used for addReferences()

#include "boost/algorithm/string.hpp" // used for string splitting
#include "ecore/EObject.hpp"
#include "persistence/base/HandlerHelper.hpp"

#include "xerces/XStr.hpp"
#include "xerces/WStr.hpp"
#include "xercesc/dom/DOMException.hpp"
#include "xercesc/util/OutOfMemoryException.hpp"

using namespace persistence::xml;

XMLSaveHandler::XMLSaveHandler ()
{
	m_doc = nullptr;
	m_currentElement = nullptr;
}

XMLSaveHandler::~XMLSaveHandler ()
{
	if ( m_doc )
	{
		m_doc->release();
	}
}

/**/
DOMDocument *XMLSaveHandler::getDOMDocument ()
{
	return m_doc;
}

bool XMLSaveHandler::createRootNode ( const std::string& name, const std::string& ns_uri )
{
	return this->createRootNode( name, ns_uri, nullptr );
}

bool XMLSaveHandler::createRootNode ( const std::string& prefix, const std::string& name, const std::string& ns_uri )
{
	return this->createRootNode( prefix, name, ns_uri, nullptr );
}

bool XMLSaveHandler::createRootNode ( const std::string& prefix, const std::string& name, const std::string& ns_uri, DOMDocumentType *doctype )
{
	m_rootPrefix = prefix;
	return this->createRootNode( prefix + ":" + name, ns_uri, doctype );
}

bool XMLSaveHandler::createRootNode ( const std::string& name, const std::string& ns_uri, DOMDocumentType *doctype )
{
	DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation( X( "Core" ) );

	if ( impl != NULL )
	{
		try
		{
			m_doc = impl->createDocument( (ns_uri.empty()) ? 0 : X( ns_uri ), // root element namespace URI.
			X( name ),         					// root element name
			doctype ); 	                		// document type object (DTD).

			m_currentElement = m_doc->getDocumentElement(); // get root element
			m_currentElement->setAttribute(X("xmi:version"), X("2.0"));
			m_currentElement->setAttribute(X("xmlns:xmi"), X("http://www.omg.org/XMI"));
			m_currentElement->setAttribute(X("xmlns:xsi"), X("http://www.w3.org/2001/XMLSchema-instance"));

			if (!m_isXSIMode && m_rootObject != nullptr)
			{
				auto iter = m_refToObject_map.find(m_rootObject);
				if (iter != m_refToObject_map.end())
				{
					addAttribute("xmi:id", iter->second);
				}
				else
				{
					std::cout << "id not found for root element" << std::endl;
				}
			}
		}
		catch ( const OutOfMemoryException& )
		{
			MSG_ERROR( MSG_FLF << "OutOfMemoryException" );
			//errorCode = 5;
			return false;
		}
		catch ( const DOMException& e )
		{
			MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
			//errorCode = 2;
			return false;
		}
		catch ( ... )
		{
			MSG_ERROR( MSG_FLF <<"An error occurred creating the document" );
			//errorCode = 3;
			return false;
		}
	}  // (impl != NULL)
	else
	{
		MSG_ERROR( MSG_FLF <<"Requested implementation is not supported" );
		//errorCode = 4;
		return false;
	}

	return true;
}

bool XMLSaveHandler::createAndAddElement ( const std::string& name )
{
	if ( m_doc == nullptr )
	{
		MSG_ERROR( MSG_FLF <<"No root-Element created first" );
		return false;
	}
	else
	{
		addChild( m_currentElement, m_doc->createElement( X( name ) ) );

		return true;
	}
}

void XMLSaveHandler::addChild ( DOMElement* parent_elem, DOMElement* child_elem )
{
	// Add child to parent Element, and set child as current Element.
	m_currentElement = (DOMElement *) parent_elem->appendChild( child_elem );
}

void XMLSaveHandler::addAttribute ( const std::string& name, const std::string& value )
{
	try
	{
		m_currentElement->setAttribute( X( name ), X( value ) );
	}
	catch ( const DOMException& e )
	{
		MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
	}
	catch ( std::exception& e )
	{
		MSG_ERROR( MSG_FLF << "Exception code is:  " << e.what() );
	}
}

void XMLSaveHandler::addReferences ( const std::string &name, std::shared_ptr<ecore::EObject> object )
{
	if (object == nullptr)
	{
		std::cerr << "XMLSaveHandler::addReferences called with object == nullptr" << std::endl;
		return;
	}
	try
	{
		std::string ref = "";
		auto iter = m_refToObject_map.find(object);
		if (iter != m_refToObject_map.end())
		{
			ref = iter->second;
		}
		else
		{
			ref = persistence::base::HandlerHelper::extractReference( object, m_rootObject, m_rootPrefix );
		}

		std::stringstream ss;
		std::string tmpStr = W( m_currentElement->getAttribute(X( name )) );

		if ( !tmpStr.empty() )
		{
			ss << tmpStr << " ";
		}
		ss << ref;

		addAttribute( name, ss.str() );
	}
	catch ( const DOMException& e )
	{
		MSG_ERROR( MSG_FLF << "DOMException code is:  " << e.code << std::endl << W( e.getMessage() ) );
	}
	catch ( std::exception& e )
	{
		MSG_ERROR( MSG_FLF << "Exception code is:  " << e.what() );
	}
}

void XMLSaveHandler::release ()
{
	if ( m_currentElement == nullptr )
	{
		MSG_ERROR( MSG_FLF << "Current DOMElement m_currentElement is nullptr" );
	}
	else
	{
		// set m_currentElement's parent node as new m_currentElement (decrease depth)
		m_currentElement = (DOMElement*) m_currentElement->getParentNode();
	}
}

void XMLSaveHandler::addTypeReference(const std::string& href, const std::string& xmitype)
{
	createAndAddElement("type");
	addAttribute("href", href);
	addAttribute("xmi:type", xmitype);
	release();
}

void XMLSaveHandler::addAttributeAsNode(const std::string& name, const std::string& value)
{
	createAndAddElement(name);
	m_currentElement->setTextContent(X(value));
	release();
}
<|endoftext|>


<commit_before>#include <type_traits>
#include <gtest/gtest.h>
#include <entt/entity/entity.hpp>
#include <entt/entity/registry.hpp>

struct entity_id {
    using entity_type = typename entt::entt_traits<entt::entity>::entity_type;

    entity_id(entity_type value = entt::null)
        : entt{value}
    {}

    entity_id(const entity_id &other)
        : entt{other.entt}
    {}

    operator entity_type() const {
        return entt;
    }

private:
    entity_type entt;
};

template<>
struct entt::entt_traits<entity_id>: entt::entt_traits<entt::entity> {};

TEST(Example, CustomIdentifier) {
    entt::basic_registry<entity_id> registry{};
    entity_id entity{};

    ASSERT_FALSE(registry.valid(entity));
    ASSERT_TRUE(entity == entt::null);

    entity = registry.create();

    ASSERT_TRUE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);

    ASSERT_FALSE((registry.all_of<int, char>(entity)));
    ASSERT_EQ(registry.try_get<int>(entity), nullptr);

    registry.emplace<int>(entity, 42);

    ASSERT_TRUE((registry.any_of<int, char>(entity)));
    ASSERT_EQ(registry.get<int>(entity), 42);

    registry.destroy(entity);

    ASSERT_FALSE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);

    entity = registry.create();

    ASSERT_TRUE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);
}
<commit_msg>test: refined custom id example<commit_after>#include <type_traits>
#include <gtest/gtest.h>
#include <entt/entity/entity.hpp>
#include <entt/entity/registry.hpp>

struct entity_id {
    using entity_type = typename entt::entt_traits<entt::entity>::entity_type;
    static constexpr auto null = entt::null;

    constexpr entity_id(entity_type value = null)
        : entt{value}
    {}

    constexpr entity_id(const entity_id &other)
        : entt{other.entt}
    {}

    constexpr operator entity_type() const {
        return entt;
    }

private:
    entity_type entt;
};

template<>
struct entt::entt_traits<entity_id>: entt::entt_traits<entt::entity> {};

TEST(Example, CustomIdentifier) {
    entt::basic_registry<entity_id> registry{};
    entity_id entity{};

    ASSERT_FALSE(registry.valid(entity));
    ASSERT_TRUE(entity == entt::null);

    entity = registry.create();

    ASSERT_TRUE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);

    ASSERT_FALSE((registry.all_of<int, char>(entity)));
    ASSERT_EQ(registry.try_get<int>(entity), nullptr);

    registry.emplace<int>(entity, 42);

    ASSERT_TRUE((registry.any_of<int, char>(entity)));
    ASSERT_EQ(registry.get<int>(entity), 42);

    registry.destroy(entity);

    ASSERT_FALSE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);

    entity = registry.create();

    ASSERT_TRUE(registry.valid(entity));
    ASSERT_TRUE(entity != entt::null);
}
<|endoftext|>


<commit_before>#include "HalideRuntime.h"

#include <math.h>
#include <stdio.h>

#include "example.h"
#include "static_image.h"

const int kSize = 32;

void verify(const Image<int> &img, float compiletime_factor, float runtime_factor, int channels) {
    for (int i = 0; i < kSize; i++) {
        for (int j = 0; j < kSize; j++) {
            for (int c = 0; c < channels; c++) {
                int expected = (int32_t)(compiletime_factor * runtime_factor * c * (i > j ? i : j));
                if (img(i, j, c) != expected) {
                    printf("img[%d, %d, %d] = %d (expected %d)\n", i, j, c, img(i, j, c), expected);
                    exit(-1);
                }
            }
        }
    }
}

int main(int argc, char **argv) {

  Image<int32_t> output(kSize, kSize, 3);

  // For Ahead-of-time compilation, we don't get to customize any GeneratorParams:
  // they were baked into the object code by our build system. These are the default values
  // for Example (replicated here to use in verify()).
  const float compiletime_factor = 1.0f;
  const int channels = 3;

  // We can, of course, pass whatever values for Param/ImageParam that we like.
  example(3.3f, output);
  verify(output, compiletime_factor, 3.3f, channels);

  example(-1.234f, output);
  verify(output, compiletime_factor, -1.234f, channels);

  printf("Success!\n");
  return 0;
}<commit_msg>Make floating point test more stable<commit_after>#include "HalideRuntime.h"

#include <math.h>
#include <stdio.h>

#include "example.h"
#include "static_image.h"

const int kSize = 32;

void verify(const Image<int> &img, float compiletime_factor, float runtime_factor, int channels) {
    for (int i = 0; i < kSize; i++) {
        for (int j = 0; j < kSize; j++) {
            for (int c = 0; c < channels; c++) {
                int expected = (int32_t)(compiletime_factor * runtime_factor * c * (i > j ? i : j));
                if (img(i, j, c) != expected) {
                    printf("img[%d, %d, %d] = %d (expected %d)\n", i, j, c, img(i, j, c), expected);
                    exit(-1);
                }
            }
        }
    }
}

int main(int argc, char **argv) {

  Image<int32_t> output(kSize, kSize, 3);

  // For Ahead-of-time compilation, we don't get to customize any GeneratorParams:
  // they were baked into the object code by our build system. These are the default values
  // for Example (replicated here to use in verify()).
  const float compiletime_factor = 1.0f;
  const int channels = 3;

  // We can, of course, pass whatever values for Param/ImageParam that we like.
  example(3.3245f, output);
  verify(output, compiletime_factor, 3.3245f, channels);

  example(-1.234f, output);
  verify(output, compiletime_factor, -1.234f, channels);

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


<commit_before>
/// @file ViewerManager.cpp Launches graphic viewers. Class definitions.

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#include <iostream>
#include <stdlib.h>
#include "ViewerManager.hpp"

namespace vplot
{
   ViewerManager::ViewerManager(const std::string& envVar)
   {
      const char* envVarValue = getenv(envVar.c_str());
      if (envVarValue!=NULL)
          viewerList.push_back(envVarValue);
   }

   void ViewerManager::registerViewer(const std::string& viewer)
   {
      using namespace std;

      list<string>::iterator it=find(viewerList.begin(), viewerList.end(), viewer);
      if (it==viewerList.end())
          viewerList.push_back(viewer);
   }

   bool ViewerManager::view(const std::string& fileName) throw (VPlotException)
   {
      using namespace std;
      bool worked=false;

      list<string>::iterator viewer;
      for (viewer=viewerList.begin(); viewer!=viewerList.end(); viewer++)
      {
         std::cout << "Going to launch " << *viewer << std::endl;
         string command = (*viewer) + " " + fileName;
         if (system(command.c_str())==0)
	 {
	    worked=true;
	    break;
         }
         std::cout << "... couldn't execute: " << command << std::endl;
      }

      return worked;
   }

} // namespace vplot

<commit_msg>Added an include for the better, non-creative compilers.<commit_after>
/// @file ViewerManager.cpp Launches graphic viewers. Class definitions.

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#include <iostream>
#include <stdlib.h>
#include <algorithm>

#include "ViewerManager.hpp"

namespace vplot
{
   ViewerManager::ViewerManager(const std::string& envVar)
   {
      const char* envVarValue = getenv(envVar.c_str());
      if (envVarValue!=NULL)
          viewerList.push_back(envVarValue);
   }

   void ViewerManager::registerViewer(const std::string& viewer)
   {
      using namespace std;

      list<string>::iterator it=find(viewerList.begin(), viewerList.end(), viewer);
      if (it==viewerList.end())
          viewerList.push_back(viewer);
   }

   bool ViewerManager::view(const std::string& fileName) throw (VPlotException)
   {
      using namespace std;
      bool worked=false;

      list<string>::iterator viewer;
      for (viewer=viewerList.begin(); viewer!=viewerList.end(); viewer++)
      {
         std::cout << "Going to launch " << *viewer << std::endl;
         string command = (*viewer) + " " + fileName;
         if (system(command.c_str())==0)
	 {
	    worked=true;
	    break;
         }
         std::cout << "... couldn't execute: " << command << std::endl;
      }

      return worked;
   }

} // namespace vplot

<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/thread.hpp"
#include "libbirch/type.hpp"
#include "libbirch/Shape.hpp"
#include "libbirch/Iterator.hpp"
#include "libbirch/Eigen.hpp"
#include "libbirch/ReadersWriterLock.hpp"

namespace libbirch {
/**
 * Array.
 *
 * @tparam T Value type.
 * @tparam F Shape type.
 */
template<class T, class F>
class Array {
  template<class U, class G> friend class Array;
public:
  using this_type = Array<T,F>;
  using value_type = T;
  using shape_type = F;
  using eigen_type = typename eigen_type<this_type>::type;
  using eigen_stride_type = typename eigen_stride_type<this_type>::type;

  /**
   * Constructor.
   */
  Array() :
      shape(),
      buffer(nullptr),
      isView(false) {
    assert(shape.volume() == 0);
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   */
  Array(const F& shape) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    initialize();
  }

  /**
   * Constructor.
   *
   * @tparam ...Args Constructor parameter types.
   *
   * @param shape Shape.
   * @param args Constructor arguments.
   */
  template<class... Args, std::enable_if_t<std::is_constructible<T,Args...>::value,int> = 0>
  Array(const F& shape, Args&&... args) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    initialize(std::forward<Args>(args)...);
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   * @param values Values.
   */
  template<class G = F, std::enable_if_t<G::count() == 1,int> = 0>
  Array(const std::initializer_list<T>& values) :
      shape(values.size()),
      buffer(nullptr),
      isView(false) {
    allocate();
    std::uninitialized_copy(values.begin(), values.end(), begin());
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   * @param values Values.
   */
  template<class G = F, std::enable_if_t<G::count() == 2,int> = 0>
  Array(const std::initializer_list<std::initializer_list<T>>& values) :
      shape(values.size(), values.begin()->size()),
      buffer(nullptr),
      isView(false) {
    allocate();
    auto ptr = buf();
    for (auto row : values) {
      for (auto value : row) {
        new (ptr++) T(value);
      }
    }
  }

  /**
   * Constructor.
   *
   * @param l Lambda called to construct each element.
   * @param shape Shape.
   */
  template<class L>
  Array(const L& l, const F& shape) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    int64_t n = 0;
    for (auto iter = begin(); iter != end(); ++iter) {
      new (&*iter) T(l(n++));
    }
  }

  /**
   * Copy constructor.
   */
  Array(const Array& o) :
      shape(o.shape.compact()),
      buffer(nullptr),
      isView(false) {
    allocate();
    uninitialized_copy(o);
  }

  /**
   * Generic copy constructor.
   */
  template<class U, class G, std::enable_if_t<F::count() == G::count() &&
      std::is_convertible<U,T>::value,int> = 0>
  Array(const Array<U,G>& o) :
      shape(o.shape.compact()),
      buffer(nullptr),
      isView(false) {
    allocate();
    uninitialized_copy(o);
  }

  /**
   * Move constructor.
   */
  Array(Array&& o) : Array() {
    if (!o.isView) {
      swap(o);
    } else {
      shape = o.shape.compact();
      allocate();
      uninitialized_copy(o);
    }
  }

  /**
   * Destructor.
   */
  ~Array() {
    release();
  }

  /**
   * Copy assignment.
   */
  Array& operator=(const Array& o) {
    assign(o);
    return *this;
  }

  /**
   * Move assignment.
   */
  Array& operator=(Array&& o) {
    if (!isView && !o.isView) {
      swap(o);
    } else {
      assign(o);
    }
    return *this;
  }

  /**
   * Copy assignment. For a view the shapes of the two arrays must
   * conform, otherwise a resize is permitted.
   */
  void assign(const Array<T,F>& o) {
    if (isView) {
      libbirch_assert_msg_(o.shape.conforms(shape), "array sizes are different");
      copy(o);
    } else {
      Array<T,F> tmp(o);
      swap(tmp);
    }
  }

  /**
   * Number of elements.
   */
  auto size() const {
    return shape.size();
  }

  /**
   * Number of elements allocated.
   */
  auto volume() const {
    return shape.volume();
  }

  /**
   * @name Element access.
   */
  ///@{
  /**
   * Iterator pointing to the first element.
   *
   * Iterators are used to access the elements of an array sequentially.
   * Elements are visited in the order in which they are stored in memory;
   * the rightmost dimension is the fastest moving (for a matrix, this is
   * "row major" order).
   */
  Iterator<T,F> begin() {
    return Iterator<T,F>(buf(), shape);
  }
  Iterator<T,F> begin() const {
    return Iterator<T,F>(buf(), shape);
  }
  Iterator<T,F> end() {
    return begin() + size();
  }
  Iterator<T,F> end() const {
    return begin() + size();
  }

  /**
   * Slice.
   *
   * @tparam V Slice type.
   *
   * @param slice Slice.
   *
   * @return The resulting view or element.
   */
  template<class V, std::enable_if_t<V::rangeCount() != 0,int> = 0>
  auto slice(const V& slice) {
    return Array<T,decltype(shape(slice))>(shape(slice), buffer,
        shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() != 0,int> = 0>
  auto slice(const V& slice) const {
    return Array<T,decltype(shape(slice))>(shape(slice), buffer,
        shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() == 0,int> = 0>
  auto& slice(const V& slice) {
    return *(buf() + shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() == 0,int> = 0>
  auto slice(const V& slice) const {
    return *(buf() + shape.serial(slice));
  }

  /**
   * Slice.
   *
   * @tparam ...Args Slice argument types.
   *
   * @param args... Slice arguments.
   *
   * @return The resulting view or element.
   */
  template<class... Args>
  decltype(auto) operator()(Args&&... args) {
    return slice(make_slice(std::forward<Args>(args)...));
  }
  template<class... Args>
  decltype(auto) operator()(Args&&... args) const {
    return slice(make_slice(std::forward<Args>(args)...));
  }
  ///@}

  /**
   * Compare.
   */
  template<class U, class G>
  bool operator==(const Array<U,G>& o) const {
    return std::equal(begin(), end(), o.begin());
  }
  template<class U, class G>
  bool operator!=(const Array<U,G>& o) const {
    return !(*this == o);
  }

  /**
   * @name Resize
   */
  ///@{
  /**
   * For a one-dimensional array, push an element onto the end. This increases
   * the array size by one.
   *
   * @param x Value.
   */
  void push(const T& x) {
    insert(size(), x);
  }

  /**
   * For a one-dimensional array, insert an element at a given position. This
   * increases the array size by one.
   *
   * @param i Position.
   * @param x Value.
   */
  void insert(const int64_t i, const T& x) {
    static_assert(F::count() == 1, "can only enlarge one-dimensional arrays");
    assert(!isView);

    auto n = size();
    auto s = F(n + 1);
    if (!buffer) {
      Array<T,F> tmp(s, x);
      swap(tmp);
    } else {
      buffer = (T*)std::realloc(buffer, s.volume()*sizeof(T));
      std::memmove((void*)(buf() + i + 1), (void*)(buf() + i), (n - i)*sizeof(T));
      new (buf() + i) T(x);
      shape = s;
    }
  }

  /**
   * For a one-dimensional array, erase elements from a given position. This
   * decreases the array size by the number of elements.
   *
   * @param i Position.
   * @param len Number of elements to erase.
   */
  void erase(const int64_t i, const int64_t len = 1) {
    static_assert(F::count() == 1, "can only shrink one-dimensional arrays");
    assert(!isView);
    assert(len > 0);
    assert(size() >= len);

    auto n = size();
    auto s = F(n - len);
    if (s.size() == 0) {
      release();
    } else {
      for (int j = i; j < i + len; ++j) {
        buf()[j].~T();
      }
      std::memmove((void*)(buf() + i), (void*)(buf() + i + len), (n - len - i)*sizeof(T));
      buffer = (T*)std::realloc(buffer, s.volume()*sizeof(T));
    }
    shape = s;
  }
  ///@}

  /**
   * @name Eigen integration
   */
  ///@{
  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  operator eigen_type() const {
    return toEigen();
  }

  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  auto toEigen() {
    return eigen_type(buf(), rows(), cols(), eigen_stride_type(rowStride(),
        colStride()));
  }

  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  auto toEigen() const {
    return eigen_type(buf(), rows(), cols(), eigen_stride_type(rowStride(),
        colStride()));
  }

  /**
   * Construct from Eigen Matrix expression.
   */
  template<class EigenType, std::enable_if_t<is_eigen_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::MatrixBase<EigenType>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Construct from Eigen DiagonalWrapper expression.
   */
  template<class EigenType, std::enable_if_t<is_diagonal_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::DiagonalWrapper<EigenType>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Construct from Eigen TriangularView expression.
   */
  template<class EigenType, unsigned Mode, std::enable_if_t<is_triangle_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::TriangularView<EigenType,Mode>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Number of rows. For a vectoor, this is the length.
   */
  auto rows() const {
    assert(1 <= F::count() && F::count() <= 2);
    return shape.length(0);
  }

  /**
   * Number of columns. For a vector, this is 1.
   */
  auto cols() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? 1 : shape.length(1);
  }

  /**
   * Stride between rows.
   */
  auto rowStride() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? shape.volume() : shape.stride(0);
  }

  /**
   * Stride between columns.
   */
  auto colStride() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? shape.stride(0) : shape.stride(1);
  }
  ///@}

private:
  /**
   * Constructor for views.
   */
  Array(const F& shape, T* buffer, int64_t offset) :
      shape(shape),
      buffer(buffer + offset),
      isView(true) {
    //
  }

  /**
   * Raw pointer to underlying buffer.
   */
  T* buf() const {
    return buffer;
  }

  /**
   * Swap with another array.
   */
  void swap(Array<T,F>& o) {
    assert(!isView);
    assert(!o.isView);
    std::swap(shape, o.shape);
    std::swap(buffer, o.buffer);
  }

  /**
   * Allocate memory for array, leaving uninitialized.
   */
  void allocate() {
    assert(!buffer);
    size_t bytes = volume()*sizeof(T);
    if (bytes > 0) {
      buffer = (T*)std::malloc(bytes);
    }
  }

  /**
   * Deallocate memory of array.
   */
  void release() {
    if (!isView) {
      size_t bytes = volume()*sizeof(T);
      if (bytes > 0) {
        std::destroy(begin(), end());
        std::free(buffer);
        buffer = nullptr;
      }
    }
  }

  /**
   * Initialize allocated memory.
   *
   * @param args Constructor arguments.
   */
  template<class ... Args, std::enable_if_t<std::is_constructible<T,Args...>::value,int> = 0>
  void initialize(Args&&... args) {
    auto iter = begin();
    auto last = end();
    for (; iter != last; ++iter) {
      new (&*iter) T(std::forward<Args>(args)...);
    }
  }

  /**
   * Assign from another array.
   */
  template<class U>
  void copy(const U& o) {
    auto n = std::min(size(), o.size());
    auto begin1 = o.begin();
    auto end1 = begin1 + n;
    auto begin2 = begin();
    auto end2 = begin2 + n;
    if (inside(begin1, end1, begin2)) {
      std::copy_backward(begin1, end1, end2);
    } else {
      std::copy(begin1, end1, begin2);
    }
  }

  /**
   * Copy from another array.
   */
  template<class U>
  void uninitialized_copy(const U& o) {
    auto n = std::min(size(), o.size());
    auto begin1 = o.begin();
    auto end1 = begin1 + n;
    auto begin2 = begin();
    for (; begin1 != end1; ++begin1, ++begin2) {
      new (&*begin2) T(*begin1);
    }
  }

  /**
   * Shape.
   */
  F shape;

  /**
   * Buffer.
   */
  T* buffer;

  /**
   * Is this a view of another array? A view has stricter assignment
   * semantics, as it cannot be resized or moved.
   */
  bool isView;
};

/**
 * Default array for `D` dimensions.
 */
template<class T, int D>
using DefaultArray = Array<T,typename DefaultShape<D>::type>;

}
<commit_msg>Addressed compile warnings on use of realloc().<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/thread.hpp"
#include "libbirch/type.hpp"
#include "libbirch/Shape.hpp"
#include "libbirch/Iterator.hpp"
#include "libbirch/Eigen.hpp"
#include "libbirch/ReadersWriterLock.hpp"

namespace libbirch {
/**
 * Array.
 *
 * @tparam T Value type.
 * @tparam F Shape type.
 */
template<class T, class F>
class Array {
  template<class U, class G> friend class Array;
public:
  using this_type = Array<T,F>;
  using value_type = T;
  using shape_type = F;
  using eigen_type = typename eigen_type<this_type>::type;
  using eigen_stride_type = typename eigen_stride_type<this_type>::type;

  /**
   * Constructor.
   */
  Array() :
      shape(),
      buffer(nullptr),
      isView(false) {
    assert(shape.volume() == 0);
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   */
  Array(const F& shape) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    initialize();
  }

  /**
   * Constructor.
   *
   * @tparam ...Args Constructor parameter types.
   *
   * @param shape Shape.
   * @param args Constructor arguments.
   */
  template<class... Args, std::enable_if_t<std::is_constructible<T,Args...>::value,int> = 0>
  Array(const F& shape, Args&&... args) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    initialize(std::forward<Args>(args)...);
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   * @param values Values.
   */
  template<class G = F, std::enable_if_t<G::count() == 1,int> = 0>
  Array(const std::initializer_list<T>& values) :
      shape(values.size()),
      buffer(nullptr),
      isView(false) {
    allocate();
    std::uninitialized_copy(values.begin(), values.end(), begin());
  }

  /**
   * Constructor.
   *
   * @param shape Shape.
   * @param values Values.
   */
  template<class G = F, std::enable_if_t<G::count() == 2,int> = 0>
  Array(const std::initializer_list<std::initializer_list<T>>& values) :
      shape(values.size(), values.begin()->size()),
      buffer(nullptr),
      isView(false) {
    allocate();
    auto ptr = buf();
    for (auto row : values) {
      for (auto value : row) {
        new (ptr++) T(value);
      }
    }
  }

  /**
   * Constructor.
   *
   * @param l Lambda called to construct each element.
   * @param shape Shape.
   */
  template<class L>
  Array(const L& l, const F& shape) :
      shape(shape),
      buffer(nullptr),
      isView(false) {
    allocate();
    int64_t n = 0;
    for (auto iter = begin(); iter != end(); ++iter) {
      new (&*iter) T(l(n++));
    }
  }

  /**
   * Copy constructor.
   */
  Array(const Array& o) :
      shape(o.shape.compact()),
      buffer(nullptr),
      isView(false) {
    allocate();
    uninitialized_copy(o);
  }

  /**
   * Generic copy constructor.
   */
  template<class U, class G, std::enable_if_t<F::count() == G::count() &&
      std::is_convertible<U,T>::value,int> = 0>
  Array(const Array<U,G>& o) :
      shape(o.shape.compact()),
      buffer(nullptr),
      isView(false) {
    allocate();
    uninitialized_copy(o);
  }

  /**
   * Move constructor.
   */
  Array(Array&& o) : Array() {
    if (!o.isView) {
      swap(o);
    } else {
      shape = o.shape.compact();
      allocate();
      uninitialized_copy(o);
    }
  }

  /**
   * Destructor.
   */
  ~Array() {
    release();
  }

  /**
   * Copy assignment.
   */
  Array& operator=(const Array& o) {
    assign(o);
    return *this;
  }

  /**
   * Move assignment.
   */
  Array& operator=(Array&& o) {
    if (!isView && !o.isView) {
      swap(o);
    } else {
      assign(o);
    }
    return *this;
  }

  /**
   * Copy assignment. For a view the shapes of the two arrays must
   * conform, otherwise a resize is permitted.
   */
  void assign(const Array<T,F>& o) {
    if (isView) {
      libbirch_assert_msg_(o.shape.conforms(shape), "array sizes are different");
      copy(o);
    } else {
      Array<T,F> tmp(o);
      swap(tmp);
    }
  }

  /**
   * Number of elements.
   */
  auto size() const {
    return shape.size();
  }

  /**
   * Number of elements allocated.
   */
  auto volume() const {
    return shape.volume();
  }

  /**
   * @name Element access.
   */
  ///@{
  /**
   * Iterator pointing to the first element.
   *
   * Iterators are used to access the elements of an array sequentially.
   * Elements are visited in the order in which they are stored in memory;
   * the rightmost dimension is the fastest moving (for a matrix, this is
   * "row major" order).
   */
  Iterator<T,F> begin() {
    return Iterator<T,F>(buf(), shape);
  }
  Iterator<T,F> begin() const {
    return Iterator<T,F>(buf(), shape);
  }
  Iterator<T,F> end() {
    return begin() + size();
  }
  Iterator<T,F> end() const {
    return begin() + size();
  }

  /**
   * Slice.
   *
   * @tparam V Slice type.
   *
   * @param slice Slice.
   *
   * @return The resulting view or element.
   */
  template<class V, std::enable_if_t<V::rangeCount() != 0,int> = 0>
  auto slice(const V& slice) {
    return Array<T,decltype(shape(slice))>(shape(slice), buffer,
        shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() != 0,int> = 0>
  auto slice(const V& slice) const {
    return Array<T,decltype(shape(slice))>(shape(slice), buffer,
        shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() == 0,int> = 0>
  auto& slice(const V& slice) {
    return *(buf() + shape.serial(slice));
  }
  template<class V, std::enable_if_t<V::rangeCount() == 0,int> = 0>
  auto slice(const V& slice) const {
    return *(buf() + shape.serial(slice));
  }

  /**
   * Slice.
   *
   * @tparam ...Args Slice argument types.
   *
   * @param args... Slice arguments.
   *
   * @return The resulting view or element.
   */
  template<class... Args>
  decltype(auto) operator()(Args&&... args) {
    return slice(make_slice(std::forward<Args>(args)...));
  }
  template<class... Args>
  decltype(auto) operator()(Args&&... args) const {
    return slice(make_slice(std::forward<Args>(args)...));
  }
  ///@}

  /**
   * Compare.
   */
  template<class U, class G>
  bool operator==(const Array<U,G>& o) const {
    return std::equal(begin(), end(), o.begin());
  }
  template<class U, class G>
  bool operator!=(const Array<U,G>& o) const {
    return !(*this == o);
  }

  /**
   * @name Resize
   */
  ///@{
  /**
   * For a one-dimensional array, push an element onto the end. This increases
   * the array size by one.
   *
   * @param x Value.
   */
  void push(const T& x) {
    insert(size(), x);
  }

  /**
   * For a one-dimensional array, insert an element at a given position. This
   * increases the array size by one.
   *
   * @param i Position.
   * @param x Value.
   */
  void insert(const int64_t i, const T& x) {
    static_assert(F::count() == 1, "can only enlarge one-dimensional arrays");
    assert(!isView);

    auto n = size();
    auto s = F(n + 1);
    if (!buffer) {
      Array<T,F> tmp(s, x);
      swap(tmp);
    } else {
      buffer = (T*)std::realloc((void*)buffer, s.volume()*sizeof(T));
      std::memmove((void*)(buf() + i + 1), (void*)(buf() + i), (n - i)*sizeof(T));
      new (buf() + i) T(x);
      shape = s;
    }
  }

  /**
   * For a one-dimensional array, erase elements from a given position. This
   * decreases the array size by the number of elements.
   *
   * @param i Position.
   * @param len Number of elements to erase.
   */
  void erase(const int64_t i, const int64_t len = 1) {
    static_assert(F::count() == 1, "can only shrink one-dimensional arrays");
    assert(!isView);
    assert(len > 0);
    assert(size() >= len);

    auto n = size();
    auto s = F(n - len);
    if (s.size() == 0) {
      release();
    } else {
      for (int j = i; j < i + len; ++j) {
        buf()[j].~T();
      }
      std::memmove((void*)(buf() + i), (void*)(buf() + i + len), (n - len - i)*sizeof(T));
      buffer = (T*)std::realloc((void*)buffer, s.volume()*sizeof(T));
    }
    shape = s;
  }
  ///@}

  /**
   * @name Eigen integration
   */
  ///@{
  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  operator eigen_type() const {
    return toEigen();
  }

  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  auto toEigen() {
    return eigen_type(buf(), rows(), cols(), eigen_stride_type(rowStride(),
        colStride()));
  }

  template<class Check = T, std::enable_if_t<std::is_arithmetic<Check>::value,int> = 0>
  auto toEigen() const {
    return eigen_type(buf(), rows(), cols(), eigen_stride_type(rowStride(),
        colStride()));
  }

  /**
   * Construct from Eigen Matrix expression.
   */
  template<class EigenType, std::enable_if_t<is_eigen_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::MatrixBase<EigenType>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Construct from Eigen DiagonalWrapper expression.
   */
  template<class EigenType, std::enable_if_t<is_diagonal_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::DiagonalWrapper<EigenType>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Construct from Eigen TriangularView expression.
   */
  template<class EigenType, unsigned Mode, std::enable_if_t<is_triangle_compatible<this_type,EigenType>::value,int> = 0>
  Array(const Eigen::TriangularView<EigenType,Mode>& o) :
      shape(o.rows(), o.cols()),
      buffer(nullptr),
      isView(false) {
    allocate();
    toEigen() = o;
  }

  /**
   * Number of rows. For a vectoor, this is the length.
   */
  auto rows() const {
    assert(1 <= F::count() && F::count() <= 2);
    return shape.length(0);
  }

  /**
   * Number of columns. For a vector, this is 1.
   */
  auto cols() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? 1 : shape.length(1);
  }

  /**
   * Stride between rows.
   */
  auto rowStride() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? shape.volume() : shape.stride(0);
  }

  /**
   * Stride between columns.
   */
  auto colStride() const {
    assert(1 <= F::count() && F::count() <= 2);
    return F::count() == 1 ? shape.stride(0) : shape.stride(1);
  }
  ///@}

private:
  /**
   * Constructor for views.
   */
  Array(const F& shape, T* buffer, int64_t offset) :
      shape(shape),
      buffer(buffer + offset),
      isView(true) {
    //
  }

  /**
   * Raw pointer to underlying buffer.
   */
  T* buf() const {
    return buffer;
  }

  /**
   * Swap with another array.
   */
  void swap(Array<T,F>& o) {
    assert(!isView);
    assert(!o.isView);
    std::swap(shape, o.shape);
    std::swap(buffer, o.buffer);
  }

  /**
   * Allocate memory for array, leaving uninitialized.
   */
  void allocate() {
    assert(!buffer);
    size_t bytes = volume()*sizeof(T);
    if (bytes > 0) {
      buffer = (T*)std::malloc(bytes);
    }
  }

  /**
   * Deallocate memory of array.
   */
  void release() {
    if (!isView) {
      size_t bytes = volume()*sizeof(T);
      if (bytes > 0) {
        std::destroy(begin(), end());
        std::free(buffer);
        buffer = nullptr;
      }
    }
  }

  /**
   * Initialize allocated memory.
   *
   * @param args Constructor arguments.
   */
  template<class ... Args, std::enable_if_t<std::is_constructible<T,Args...>::value,int> = 0>
  void initialize(Args&&... args) {
    auto iter = begin();
    auto last = end();
    for (; iter != last; ++iter) {
      new (&*iter) T(std::forward<Args>(args)...);
    }
  }

  /**
   * Assign from another array.
   */
  template<class U>
  void copy(const U& o) {
    auto n = std::min(size(), o.size());
    auto begin1 = o.begin();
    auto end1 = begin1 + n;
    auto begin2 = begin();
    auto end2 = begin2 + n;
    if (inside(begin1, end1, begin2)) {
      std::copy_backward(begin1, end1, end2);
    } else {
      std::copy(begin1, end1, begin2);
    }
  }

  /**
   * Copy from another array.
   */
  template<class U>
  void uninitialized_copy(const U& o) {
    auto n = std::min(size(), o.size());
    auto begin1 = o.begin();
    auto end1 = begin1 + n;
    auto begin2 = begin();
    for (; begin1 != end1; ++begin1, ++begin2) {
      new (&*begin2) T(*begin1);
    }
  }

  /**
   * Shape.
   */
  F shape;

  /**
   * Buffer.
   */
  T* buffer;

  /**
   * Is this a view of another array? A view has stricter assignment
   * semantics, as it cannot be resized or moved.
   */
  bool isView;
};

/**
 * Default array for `D` dimensions.
 */
template<class T, int D>
using DefaultArray = Array<T,typename DefaultShape<D>::type>;

}
<|endoftext|>