<commit_before>#include "unittest.hpp"
#include "rice/Data_Object.hpp"
#include "rice/Data_Type.hpp"
#include "rice/Exception.hpp"

using namespace Rice;

TESTSUITE(Data_Object);

namespace
{
  struct Foo { Foo() : x_(42) { } int x_; };

  bool test_ruby_mark__marked = false;
}

template<>
void ruby_mark(Foo * foo)
{
  test_ruby_mark__marked = true;
}

SETUP(Data_Object)
{
  ruby_init();

  if(!Data_Type<Foo>::is_bound())
  {
    Class object(rb_cObject);
    if(object.const_defined("Foo"))
    {
      object.remove_const("Foo");
    }

    define_class<Foo>("Foo");
  }
}

TESTCASE(construct_from_pointer_with_defaults)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  ASSERT_EQUAL(
      Mark_Func(Mark_Func_Foo(ruby_mark<Foo>)),
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_pointer_and_klass)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, Data_Type<Foo>::klass());
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  ASSERT_EQUAL(
      Mark_Func(Mark_Func_Foo(ruby_mark<Foo>)),
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_pointer_and_alternate_klass)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cObject);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(rb_cObject, CLASS_OF(wrapped_foo.value()));
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  ASSERT_EQUAL(
      Mark_Func(Mark_Func_Foo(ruby_mark<Foo>)),
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

namespace
{
  void dummy_mark(Foo *)
  {
  }
}

TESTCASE(construct_from_pointer_and_klass_and_mark_function)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cFoo, dummy_mark);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  ASSERT_EQUAL((void *)dummy_mark, RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

namespace
{
  void my_free(Foo * f)
  {
    delete f;
  }
}

TESTCASE(construct_from_pointer_and_klass_and_mark_and_free)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cFoo, dummy_mark, my_free);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  ASSERT_EQUAL((void *)dummy_mark, RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(my_free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_ruby_object)
{
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> data_object_foo(wrapped_foo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(construct_from_ruby_object_and_class)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> data_object_foo(wrapped_foo, rb_cFoo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(construct_from_ruby_object_and_wrong_class)
{
  Foo * foo = new Foo;
  Data_Type<Foo> rb_cFoo;
  VALUE wrapped_foo = Data_Wrap_Struct(rb_cObject, 0, Default_Allocation_Strategy<Foo>::free, foo);
  ASSERT_EXCEPTION_CHECK(
      Exception,
      Data_Object<Foo> data_object_foo(wrapped_foo, rb_cFoo),
      ASSERT_EQUAL(
          Object(rb_eTypeError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(copy_construct)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> orig_data_object_foo(wrapped_foo, rb_cFoo);
  Data_Object<Foo> data_object_foo(orig_data_object_foo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(dereference)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, &*wrapped_foo);
}

TESTCASE(arrow)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(42, foo->x_);
}

TESTCASE(get)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, wrapped_foo.get());
}

// TODO: swap

TESTCASE(to_ruby)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(wrapped_foo.value(), to_ruby(wrapped_foo).value());
}

TESTCASE(from_ruby)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, from_ruby<Foo *>(wrapped_foo));
}

TESTCASE(from_ruby_const_ref)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo->x_, from_ruby<Foo const &>(wrapped_foo).x_);
}

TESTCASE(from_ruby_copy)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo->x_, from_ruby<Foo>(wrapped_foo).x_);
}

TESTCASE(ruby_mark)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);

  test_ruby_mark__marked = false;

  rb_gc_start();

  ASSERT_EQUAL(true, test_ruby_mark__marked);
}

<commit_msg>Fixed compile problem on gcc 3.x.<commit_after>#include "unittest.hpp"
#include "rice/Data_Object.hpp"
#include "rice/Data_Type.hpp"
#include "rice/Exception.hpp"

using namespace Rice;

TESTSUITE(Data_Object);

namespace
{
  struct Foo { Foo() : x_(42) { } int x_; };

  bool test_ruby_mark__marked = false;
}

template<>
void ruby_mark(Foo * foo)
{
  test_ruby_mark__marked = true;
}

SETUP(Data_Object)
{
  ruby_init();

  if(!Data_Type<Foo>::is_bound())
  {
    Class object(rb_cObject);
    if(object.const_defined("Foo"))
    {
      object.remove_const("Foo");
    }

    define_class<Foo>("Foo");
  }
}

TESTCASE(construct_from_pointer_with_defaults)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  Mark_Func expected_mark_func =
    Mark_Func(Mark_Func_Foo(ruby_mark<Foo>));
  ASSERT_EQUAL(
      expected_mark_func,
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_pointer_and_klass)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, Data_Type<Foo>::klass());
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  Mark_Func expected_mark_func =
    Mark_Func(Mark_Func_Foo(ruby_mark<Foo>));
  ASSERT_EQUAL(
      expected_mark_func,
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_pointer_and_alternate_klass)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cObject);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(rb_cObject, CLASS_OF(wrapped_foo.value()));
  typedef void (*Mark_Func)(void *);
  typedef void (*Mark_Func_Foo)(Foo *);
  Mark_Func expected_mark_func =
    Mark_Func(Mark_Func_Foo(ruby_mark<Foo>));
  ASSERT_EQUAL(
      expected_mark_func,
      RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

namespace
{
  void dummy_mark(Foo *)
  {
  }
}

TESTCASE(construct_from_pointer_and_klass_and_mark_function)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cFoo, dummy_mark);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  ASSERT_EQUAL((void *)dummy_mark, RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

namespace
{
  void my_free(Foo * f)
  {
    delete f;
  }
}

TESTCASE(construct_from_pointer_and_klass_and_mark_and_free)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo, rb_cFoo, dummy_mark, my_free);
  ASSERT_EQUAL(foo, wrapped_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), wrapped_foo.class_of());
  ASSERT_EQUAL((void *)dummy_mark, RDATA(wrapped_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(my_free),
      RUBY_DATA_FUNC(RDATA(wrapped_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(wrapped_foo.value()));
}

TESTCASE(construct_from_ruby_object)
{
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> data_object_foo(wrapped_foo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(construct_from_ruby_object_and_class)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> data_object_foo(wrapped_foo, rb_cFoo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(construct_from_ruby_object_and_wrong_class)
{
  Foo * foo = new Foo;
  Data_Type<Foo> rb_cFoo;
  VALUE wrapped_foo = Data_Wrap_Struct(rb_cObject, 0, Default_Allocation_Strategy<Foo>::free, foo);
  ASSERT_EXCEPTION_CHECK(
      Exception,
      Data_Object<Foo> data_object_foo(wrapped_foo, rb_cFoo),
      ASSERT_EQUAL(
          Object(rb_eTypeError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(copy_construct)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  VALUE wrapped_foo = Data_Wrap_Struct(Data_Type<Foo>::klass(), 0, Default_Allocation_Strategy<Foo>::free, foo);
  Data_Object<Foo> orig_data_object_foo(wrapped_foo, rb_cFoo);
  Data_Object<Foo> data_object_foo(orig_data_object_foo);
  ASSERT_EQUAL(foo, data_object_foo.get());
  ASSERT_EQUAL(Data_Type<Foo>::klass(), data_object_foo.class_of());
  ASSERT_EQUAL(RDATA(wrapped_foo), RDATA(data_object_foo.value()));
  ASSERT_EQUAL(RUBY_DATA_FUNC(0), RDATA(data_object_foo.value())->dmark);
  ASSERT_EQUAL(
      RUBY_DATA_FUNC(Default_Allocation_Strategy<Foo>::free),
      RUBY_DATA_FUNC(RDATA(data_object_foo.value())->dfree));
  ASSERT_EQUAL(foo, DATA_PTR(data_object_foo.value()));
}

TESTCASE(dereference)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, &*wrapped_foo);
}

TESTCASE(arrow)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(42, foo->x_);
}

TESTCASE(get)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, wrapped_foo.get());
}

// TODO: swap

TESTCASE(to_ruby)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(wrapped_foo.value(), to_ruby(wrapped_foo).value());
}

TESTCASE(from_ruby)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo, from_ruby<Foo *>(wrapped_foo));
}

TESTCASE(from_ruby_const_ref)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo->x_, from_ruby<Foo const &>(wrapped_foo).x_);
}

TESTCASE(from_ruby_copy)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);
  ASSERT_EQUAL(foo->x_, from_ruby<Foo>(wrapped_foo).x_);
}

TESTCASE(ruby_mark)
{
  Data_Type<Foo> rb_cFoo;
  Foo * foo = new Foo;
  Data_Object<Foo> wrapped_foo(foo);

  test_ruby_mark__marked = false;

  rb_gc_start();

  ASSERT_EQUAL(true, test_ruby_mark__marked);
}

<|endoftext|>


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

#include "GrGLTexture.h"
#include "GrGpuGL.h"

SK_DEFINE_INST_COUNT(GrGLTexID)

#define GPUGL static_cast<GrGpuGL*>(getGpu())

#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)

void GrGLTexture::init(GrGpuGL* gpu,
                       const Desc& textureDesc,
                       const GrGLRenderTarget::Desc* rtDesc) {

    GrAssert(0 != textureDesc.fTextureID);

    fTexParams.invalidate();
    fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
    fTexIDObj           = SkNEW_ARGS(GrGLTexID,
                                     (GPUGL->glInterface(),
                                      textureDesc.fTextureID,
                                      textureDesc.fIsWrapped));

    if (NULL != rtDesc) {
        GrGLIRect vp;
        vp.fLeft   = 0;
        vp.fWidth  = textureDesc.fWidth;
        vp.fBottom = 0;
        vp.fHeight = textureDesc.fHeight;

        fRenderTarget = SkNEW_ARGS(GrGLRenderTarget,
                                   (gpu, *rtDesc, vp, fTexIDObj, this));
    }
}

GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                         const Desc& textureDesc)
    : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) {
    this->init(gpu, textureDesc, NULL);
}

GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                         const Desc& textureDesc,
                         const GrGLRenderTarget::Desc& rtDesc)
    : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) {
    this->init(gpu, textureDesc, &rtDesc);
}

void GrGLTexture::onRelease() {
    GPUGL->notifyTextureDelete(this);
    if (NULL != fTexIDObj) {
        fTexIDObj->unref();
        fTexIDObj = NULL;
    }

    INHERITED::onRelease();
}

void GrGLTexture::onAbandon() {
    if (NULL != fTexIDObj) {
        fTexIDObj->abandon();
    }

    INHERITED::onAbandon();
}

GrBackendObject GrGLTexture::getTextureHandle() const {
    return fTexIDObj->id();
}
<commit_msg>Commit file accidentally left out of glc change for r8525<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLTexture.h"
#include "GrGpuGL.h"

SK_DEFINE_INST_COUNT(GrGLTexID)

#define GPUGL static_cast<GrGpuGL*>(getGpu())

#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)

void GrGLTexture::init(GrGpuGL* gpu,
                       const Desc& textureDesc,
                       const GrGLRenderTarget::Desc* rtDesc) {

    GrAssert(0 != textureDesc.fTextureID);

    fTexParams.invalidate();
    fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
    fTexIDObj           = SkNEW_ARGS(GrGLTexID,
                                     (GPUGL->glInterface(),
                                      textureDesc.fTextureID,
                                      textureDesc.fIsWrapped));

    if (NULL != rtDesc) {
        GrGLIRect vp;
        vp.fLeft   = 0;
        vp.fWidth  = textureDesc.fWidth;
        vp.fBottom = 0;
        vp.fHeight = textureDesc.fHeight;

        fRenderTarget.reset(SkNEW_ARGS(GrGLRenderTarget, (gpu, *rtDesc, vp, fTexIDObj, this)));
    }
}

GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                         const Desc& textureDesc)
    : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) {
    this->init(gpu, textureDesc, NULL);
}

GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                         const Desc& textureDesc,
                         const GrGLRenderTarget::Desc& rtDesc)
    : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) {
    this->init(gpu, textureDesc, &rtDesc);
}

void GrGLTexture::onRelease() {
    GPUGL->notifyTextureDelete(this);
    if (NULL != fTexIDObj) {
        fTexIDObj->unref();
        fTexIDObj = NULL;
    }

    INHERITED::onRelease();
}

void GrGLTexture::onAbandon() {
    if (NULL != fTexIDObj) {
        fTexIDObj->abandon();
    }

    INHERITED::onAbandon();
}

GrBackendObject GrGLTexture::getTextureHandle() const {
    return fTexIDObj->id();
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GPUFilter.h"
#include "Bitmap.h"

#include "VertexArray.h"
#include "../base/ObjectCounter.h"
#include "../base/Exception.h"
#include "../base/MathHelper.h"

#include <iostream>

using namespace std;

namespace avg {

GPUFilter::GPUFilter(const IntPoint& size, PixelFormat pfSrc, PixelFormat pfDest,
        bool bStandalone, unsigned numTextures)
    : m_pFBO(new FBO(size, pfDest, numTextures))
{
    if (bStandalone) {
        m_pSrcTex = GLTexturePtr(new GLTexture(size, pfSrc));
        m_pSrcPBO = PBOPtr(new PBO(size, pfSrc, GL_STREAM_DRAW));
    }
    ObjectCounter::get()->incRef(&typeid(*this));
}

GPUFilter::~GPUFilter()
{
    ObjectCounter::get()->decRef(&typeid(*this));
}

BitmapPtr GPUFilter::apply(BitmapPtr pBmpSource)
{
    AVG_ASSERT(m_pSrcTex);
    m_pSrcPBO->moveBmpToTexture(pBmpSource, m_pSrcTex);
    apply(m_pSrcTex);
    BitmapPtr pFilteredBmp = m_pFBO->getImage();
    BitmapPtr pDestBmp;
    if (pFilteredBmp->getPixelFormat() != pBmpSource->getPixelFormat()) {
        pDestBmp = BitmapPtr(new Bitmap(getSize(), pBmpSource->getPixelFormat()));
        pDestBmp->copyPixels(*pFilteredBmp);
    } else {
        pDestBmp = pFilteredBmp;
    }
    return pDestBmp;
}

void GPUFilter::apply(GLTexturePtr pSrcTex)
{
    m_pFBO->activate();
    m_pFBO->setupImagingProjection();
    applyOnGPU(pSrcTex);
    m_pFBO->deactivate();
    m_pFBO->copyToDestTexture();
}

GLTexturePtr GPUFilter::getDestTex(int i) const
{
    return m_pFBO->getTex(i);
}

BitmapPtr GPUFilter::getImage() const
{
    return m_pFBO->getImage();
}

FBOPtr GPUFilter::getFBO()
{
    return m_pFBO;
}

void GPUFilter::draw(GLTexturePtr pTex)
{
    pTex->activate(GL_TEXTURE0);
    m_pFBO->drawImagingVertexes();
}

const IntPoint& GPUFilter::getSize() const
{
    return m_pFBO->getSize();
}

const string& GPUFilter::getStdShaderCode() const
{
    static string sCode =
        "void unPreMultiplyAlpha(inout vec4 color)\n"
        "{\n"
        "    color.rgb /= color.a;\n"
        "}\n"
        "\n"
        "void preMultiplyAlpha(inout vec4 color)\n"
        "{\n"
        "    color.rgb *= color.a;\n"
        "}\n"
        "\n";

    return sCode;
}

void dumpKernel(int width, float* pKernel)
{
    cerr << "  Kernel width: " << width << endl;
    float sum = 0;
    for (int i=0; i<width; ++i) {
        sum += pKernel[i];
        cerr << "  " << pKernel[i] << endl;
    }
    cerr << "Sum of coefficients: " << sum << endl;
}

GLTexturePtr GPUFilter::calcBlurKernelTex(double stdDev, double opacity) const
// If opacity is -1, this is a brightness-preserving blur.
// Otherwise, opacity is the coefficient of the center pixel.
{
    int kernelCenter = int(ceil(stdDev*3));
    int kernelWidth = kernelCenter*2+1;
    float* pKernel;
    pKernel = new float[kernelWidth];
    float sum = 0;
    for (int i=0; i <= kernelCenter; ++i) {
        pKernel[kernelCenter+i] = float(exp(-i*i/(2*stdDev*stdDev))
                /sqrt(2*PI*stdDev*stdDev));
        sum += pKernel[kernelCenter+i];
        if (i != 0) {
            pKernel[kernelCenter-i] = pKernel[kernelCenter+i];
            sum += pKernel[kernelCenter-i];
        }
    }

    if (opacity == -1) {
        // This is a brightness-preserving blur.
        // Make sure the sum of coefficients is 1 despite the inaccuracies
        // introduced by using a kernel of finite size.
        for (int i=0; i<kernelWidth; ++i) {
            pKernel[i] /= sum;
        }
    } else {
        double factor = opacity/pKernel[kernelCenter];
        for (int i=0; i<kernelWidth; ++i) {
            pKernel[i] *= factor;
        }
    }
//    dumpKernel(kernelWidth, pKernel);

    IntPoint size(kernelWidth, 1);
    GLTexturePtr pTex(new GLTexture(size, I32F));
    PBO pbo(size, I32F, GL_STREAM_DRAW);
    pbo.activate();
    void * pPBOPixels = glproc::MapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "GPUFilter::calcBlurKernelTex MapBuffer()");
    int memNeeded = kernelWidth*sizeof(float);
    memcpy(pPBOPixels, pKernel, memNeeded);
    glproc::UnmapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "GPUFilter::calcBlurKernelTex UnmapBuffer()");

    pbo.movePBOToTexture(pTex);

    delete[] pKernel;
    return pTex;
}

}
<commit_msg>Fixed missing include in GPUFilter.cpp<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GPUFilter.h"
#include "Bitmap.h"

#include "VertexArray.h"
#include "../base/ObjectCounter.h"
#include "../base/Exception.h"
#include "../base/MathHelper.h"

#include <iostream>
#include <string.h>

using namespace std;

namespace avg {

GPUFilter::GPUFilter(const IntPoint& size, PixelFormat pfSrc, PixelFormat pfDest,
        bool bStandalone, unsigned numTextures)
    : m_pFBO(new FBO(size, pfDest, numTextures))
{
    if (bStandalone) {
        m_pSrcTex = GLTexturePtr(new GLTexture(size, pfSrc));
        m_pSrcPBO = PBOPtr(new PBO(size, pfSrc, GL_STREAM_DRAW));
    }
    ObjectCounter::get()->incRef(&typeid(*this));
}

GPUFilter::~GPUFilter()
{
    ObjectCounter::get()->decRef(&typeid(*this));
}

BitmapPtr GPUFilter::apply(BitmapPtr pBmpSource)
{
    AVG_ASSERT(m_pSrcTex);
    m_pSrcPBO->moveBmpToTexture(pBmpSource, m_pSrcTex);
    apply(m_pSrcTex);
    BitmapPtr pFilteredBmp = m_pFBO->getImage();
    BitmapPtr pDestBmp;
    if (pFilteredBmp->getPixelFormat() != pBmpSource->getPixelFormat()) {
        pDestBmp = BitmapPtr(new Bitmap(getSize(), pBmpSource->getPixelFormat()));
        pDestBmp->copyPixels(*pFilteredBmp);
    } else {
        pDestBmp = pFilteredBmp;
    }
    return pDestBmp;
}

void GPUFilter::apply(GLTexturePtr pSrcTex)
{
    m_pFBO->activate();
    m_pFBO->setupImagingProjection();
    applyOnGPU(pSrcTex);
    m_pFBO->deactivate();
    m_pFBO->copyToDestTexture();
}

GLTexturePtr GPUFilter::getDestTex(int i) const
{
    return m_pFBO->getTex(i);
}

BitmapPtr GPUFilter::getImage() const
{
    return m_pFBO->getImage();
}

FBOPtr GPUFilter::getFBO()
{
    return m_pFBO;
}

void GPUFilter::draw(GLTexturePtr pTex)
{
    pTex->activate(GL_TEXTURE0);
    m_pFBO->drawImagingVertexes();
}

const IntPoint& GPUFilter::getSize() const
{
    return m_pFBO->getSize();
}

const string& GPUFilter::getStdShaderCode() const
{
    static string sCode =
        "void unPreMultiplyAlpha(inout vec4 color)\n"
        "{\n"
        "    color.rgb /= color.a;\n"
        "}\n"
        "\n"
        "void preMultiplyAlpha(inout vec4 color)\n"
        "{\n"
        "    color.rgb *= color.a;\n"
        "}\n"
        "\n";

    return sCode;
}

void dumpKernel(int width, float* pKernel)
{
    cerr << "  Kernel width: " << width << endl;
    float sum = 0;
    for (int i=0; i<width; ++i) {
        sum += pKernel[i];
        cerr << "  " << pKernel[i] << endl;
    }
    cerr << "Sum of coefficients: " << sum << endl;
}

GLTexturePtr GPUFilter::calcBlurKernelTex(double stdDev, double opacity) const
// If opacity is -1, this is a brightness-preserving blur.
// Otherwise, opacity is the coefficient of the center pixel.
{
    int kernelCenter = int(ceil(stdDev*3));
    int kernelWidth = kernelCenter*2+1;
    float* pKernel;
    pKernel = new float[kernelWidth];
    float sum = 0;
    for (int i=0; i <= kernelCenter; ++i) {
        pKernel[kernelCenter+i] = float(exp(-i*i/(2*stdDev*stdDev))
                /sqrt(2*PI*stdDev*stdDev));
        sum += pKernel[kernelCenter+i];
        if (i != 0) {
            pKernel[kernelCenter-i] = pKernel[kernelCenter+i];
            sum += pKernel[kernelCenter-i];
        }
    }

    if (opacity == -1) {
        // This is a brightness-preserving blur.
        // Make sure the sum of coefficients is 1 despite the inaccuracies
        // introduced by using a kernel of finite size.
        for (int i=0; i<kernelWidth; ++i) {
            pKernel[i] /= sum;
        }
    } else {
        double factor = opacity/pKernel[kernelCenter];
        for (int i=0; i<kernelWidth; ++i) {
            pKernel[i] *= factor;
        }
    }
//    dumpKernel(kernelWidth, pKernel);

    IntPoint size(kernelWidth, 1);
    GLTexturePtr pTex(new GLTexture(size, I32F));
    PBO pbo(size, I32F, GL_STREAM_DRAW);
    pbo.activate();
    void * pPBOPixels = glproc::MapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "GPUFilter::calcBlurKernelTex MapBuffer()");
    int memNeeded = kernelWidth*sizeof(float);
    memcpy(pPBOPixels, pKernel, memNeeded);
    glproc::UnmapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "GPUFilter::calcBlurKernelTex UnmapBuffer()");

    pbo.movePBOToTexture(pTex);

    delete[] pKernel;
    return pTex;
}

}
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkMovie.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"

#include "gif_lib.h"

#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
#define DGifCloseFile(a, b) DGifCloseFile(a)
#endif

class SkGIFMovie : public SkMovie {
public:
    SkGIFMovie(SkStream* stream);
    virtual ~SkGIFMovie();

protected:
    virtual bool onGetInfo(Info*);
    virtual bool onSetTime(SkMSec);
    virtual bool onGetBitmap(SkBitmap*);

private:
    GifFileType* fGIF;
    int fCurrIndex;
    int fLastDrawIndex;
    SkBitmap fBackup;
    SkColor fPaintingColor;
};

static int Decode(GifFileType* fileType, GifByteType* out, int size) {
    SkStream* stream = (SkStream*) fileType->UserData;
    return (int) stream->read(out, size);
}

SkGIFMovie::SkGIFMovie(SkStream* stream)
{
#if GIFLIB_MAJOR < 5
    fGIF = DGifOpen( stream, Decode );
#else
    fGIF = DGifOpen( stream, Decode, nullptr );
#endif
    if (nullptr == fGIF)
        return;

    if (DGifSlurp(fGIF) != GIF_OK)
    {
        DGifCloseFile(fGIF, nullptr);
        fGIF = nullptr;
    }
    fCurrIndex = -1;
    fLastDrawIndex = -1;
    fPaintingColor = SkPackARGB32(0, 0, 0, 0);
}

SkGIFMovie::~SkGIFMovie()
{
    if (fGIF)
        DGifCloseFile(fGIF, nullptr);
}

static SkMSec savedimage_duration(const SavedImage* image)
{
    for (int j = 0; j < image->ExtensionBlockCount; j++)
    {
        if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE)
        {
            SkASSERT(image->ExtensionBlocks[j].ByteCount >= 4);
            const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes;
            return ((b[2] << 8) | b[1]) * 10;
        }
    }
    return 0;
}

bool SkGIFMovie::onGetInfo(Info* info)
{
    if (nullptr == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
        dur += savedimage_duration(&fGIF->SavedImages[i]);

    info->fDuration = dur;
    info->fWidth = fGIF->SWidth;
    info->fHeight = fGIF->SHeight;
    info->fIsOpaque = false;    // how to compute?
    return true;
}

bool SkGIFMovie::onSetTime(SkMSec time)
{
    if (nullptr == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
    {
        dur += savedimage_duration(&fGIF->SavedImages[i]);
        if (dur >= time)
        {
            fCurrIndex = i;
            return fLastDrawIndex != fCurrIndex;
        }
    }
    fCurrIndex = fGIF->ImageCount - 1;
    return true;
}

static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap,
                     int transparent, int width)
{
    for (; width > 0; width--, src++, dst++) {
        if (*src != transparent) {
            const GifColorType& col = cmap->Colors[*src];
            *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
        }
    }
}

#if GIFLIB_MAJOR < 5
static void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src,
                               const ColorMapObject* cmap, int transparent, int copyWidth,
                               int copyHeight, const GifImageDesc& imageDesc, int rowStep,
                               int startRow)
{
    int row;
    // every 'rowStep'th row, starting with row 'startRow'
    for (row = startRow; row < copyHeight; row += rowStep) {
        uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row);
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += imageDesc.Width;
    }

    // pad for rest height
    src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep);
}

static void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                          int transparent)
{
    int width = bm->width();
    int height = bm->height();
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    // deinterlace
    const unsigned char* src = (unsigned char*)frame->RasterBits;

    // group 1 - every 8th row, starting with row 0
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0);

    // group 2 - every 8th row, starting with row 4
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4);

    // group 3 - every 4th row, starting with row 2
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2);

    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1);
}
#endif

static void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                       int transparent)
{
    int width = bm->width();
    int height = bm->height();
    const unsigned char* src = (unsigned char*)frame->RasterBits;
    uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top);
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    for (; copyHeight > 0; copyHeight--) {
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += frame->ImageDesc.Width;
        dst += width;
    }
}

static void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height,
                     uint32_t col)
{
    int bmWidth = bm->width();
    int bmHeight = bm->height();
    uint32_t* dst = bm->getAddr32(left, top);
    GifWord copyWidth = width;
    if (left + copyWidth > bmWidth) {
        copyWidth = bmWidth - left;
    }

    GifWord copyHeight = height;
    if (top + copyHeight > bmHeight) {
        copyHeight = bmHeight - top;
    }

    for (; copyHeight > 0; copyHeight--) {
        sk_memset32(dst, col, copyWidth);
        dst += bmWidth;
    }
}

static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap)
{
    int transparent = -1;

    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            bool has_transparency = ((eb->Bytes[0] & 1) == 1);
            if (has_transparency) {
                transparent = (unsigned char)eb->Bytes[3];
            }
        }
    }

    if (frame->ImageDesc.ColorMap != nullptr) {
        // use local color table
        cmap = frame->ImageDesc.ColorMap;
    }

    if (cmap == nullptr || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
        SkDEBUGFAIL("bad colortable setup");
        return;
    }

#if GIFLIB_MAJOR < 5
    // before GIFLIB 5, de-interlacing wasn't done by library at load time
    if (frame->ImageDesc.Interlace) {
        blitInterlace(bm, frame, cmap, transparent);
        return;
    }
#endif

    blitNormal(bm, frame, cmap, transparent);
}

static bool checkIfWillBeCleared(const SavedImage* frame)
{
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            // check disposal method
            int disposal = ((eb->Bytes[0] >> 2) & 7);
            if (disposal == 2 || disposal == 3) {
                return true;
            }
        }
    }
    return false;
}

static void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal)
{
    *trans = false;
    *disposal = 0;
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            *trans = ((eb->Bytes[0] & 1) == 1);
            *disposal = ((eb->Bytes[0] >> 2) & 7);
        }
    }
}

// return true if area of 'target' is completely covers area of 'covered'
static bool checkIfCover(const SavedImage* target, const SavedImage* covered)
{
    if (target->ImageDesc.Left <= covered->ImageDesc.Left
        && covered->ImageDesc.Left + covered->ImageDesc.Width <=
               target->ImageDesc.Left + target->ImageDesc.Width
        && target->ImageDesc.Top <= covered->ImageDesc.Top
        && covered->ImageDesc.Top + covered->ImageDesc.Height <=
               target->ImageDesc.Top + target->ImageDesc.Height) {
        return true;
    }
    return false;
}

static void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next,
                                 SkBitmap* backup, SkColor color)
{
    // We can skip disposal process if next frame is not transparent
    // and completely covers current area
    bool curTrans;
    int curDisposal;
    getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal);
    bool nextTrans;
    int nextDisposal;
    getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal);
    if ((curDisposal == 2 || curDisposal == 3)
        && (nextTrans || !checkIfCover(next, cur))) {
        switch (curDisposal) {
        // restore to background color
        // -> 'background' means background under this image.
        case 2:
            fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top,
                     cur->ImageDesc.Width, cur->ImageDesc.Height,
                     color);
            break;

        // restore to previous
        case 3:
            bm->swap(*backup);
            break;
        }
    }

    // Save current image if next frame's disposal method == 3
    if (nextDisposal == 3) {
        const uint32_t* src = bm->getAddr32(0, 0);
        uint32_t* dst = backup->getAddr32(0, 0);
        int cnt = bm->width() * bm->height();
        memcpy(dst, src, cnt*sizeof(uint32_t));
    }
}

bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
{
    const GifFileType* gif = fGIF;
    if (nullptr == gif)
        return false;

    if (gif->ImageCount < 1) {
        return false;
    }

    const int width = gif->SWidth;
    const int height = gif->SHeight;
    if (width <= 0 || height <= 0) {
        return false;
    }

    // no need to draw
    if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) {
        return true;
    }

    int startIndex = fLastDrawIndex + 1;
    if (fLastDrawIndex < 0 || !bm->readyToDraw()) {
        // first time

        startIndex = 0;

        // create bitmap
        if (!bm->tryAllocN32Pixels(width, height)) {
            return false;
        }
        // create bitmap for backup
        if (!fBackup.tryAllocN32Pixels(width, height)) {
            return false;
        }
    } else if (startIndex > fCurrIndex) {
        // rewind to 1st frame for repeat
        startIndex = 0;
    }

    int lastIndex = fCurrIndex;
    if (lastIndex < 0) {
        // first time
        lastIndex = 0;
    } else if (lastIndex > fGIF->ImageCount - 1) {
        // this block must not be reached.
        lastIndex = fGIF->ImageCount - 1;
    }

    SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
    if (gif->SColorMap != nullptr) {
        const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor];
        bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
    }

    // draw each frames - not intelligent way
    for (int i = startIndex; i <= lastIndex; i++) {
        const SavedImage* cur = &fGIF->SavedImages[i];
        if (i == 0) {
            bool trans;
            int disposal;
            getTransparencyAndDisposalMethod(cur, &trans, &disposal);
            if (!trans && gif->SColorMap != nullptr) {
                fPaintingColor = bgColor;
            } else {
                fPaintingColor = SkColorSetARGB(0, 0, 0, 0);
            }

            bm->eraseColor(fPaintingColor);
            fBackup.eraseColor(fPaintingColor);
        } else {
            // Dispose previous frame before move to next frame.
            const SavedImage* prev = &fGIF->SavedImages[i-1];
            disposeFrameIfNeeded(bm, prev, cur, &fBackup, fPaintingColor);
        }

        // Draw frame
        // We can skip this process if this index is not last and disposal
        // method == 2 or method == 3
        if (i == lastIndex || !checkIfWillBeCleared(cur)) {
            drawFrame(bm, cur, gif->SColorMap);
        }
    }

    // save index
    fLastDrawIndex = lastIndex;
    return true;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkTRegistry.h"

SkMovie* Factory(SkStreamRewindable* stream) {
    char buf[GIF_STAMP_LEN];
    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
            // must rewind here, since our construct wants to re-read the data
            stream->rewind();
            return new SkGIFMovie(stream);
        }
    }
    return nullptr;
}

static SkTRegistry<SkMovie*(*)(SkStreamRewindable*)> gReg(Factory);
<commit_msg>Fix out of bounds memory read in GIFMovie.cpp am: 16882f7212 am: d2456e3a12 am: ffc0958605 am: df18259ff1 am: c9b947def7 am: 09ad23b21e am: 716de6b276 am: d1fb426850<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkMovie.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"

#include "gif_lib.h"

#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
#define DGifCloseFile(a, b) DGifCloseFile(a)
#endif

class SkGIFMovie : public SkMovie {
public:
    SkGIFMovie(SkStream* stream);
    virtual ~SkGIFMovie();

protected:
    virtual bool onGetInfo(Info*);
    virtual bool onSetTime(SkMSec);
    virtual bool onGetBitmap(SkBitmap*);

private:
    GifFileType* fGIF;
    int fCurrIndex;
    int fLastDrawIndex;
    SkBitmap fBackup;
    SkColor fPaintingColor;
};

static int Decode(GifFileType* fileType, GifByteType* out, int size) {
    SkStream* stream = (SkStream*) fileType->UserData;
    return (int) stream->read(out, size);
}

SkGIFMovie::SkGIFMovie(SkStream* stream)
{
#if GIFLIB_MAJOR < 5
    fGIF = DGifOpen( stream, Decode );
#else
    fGIF = DGifOpen( stream, Decode, nullptr );
#endif
    if (nullptr == fGIF)
        return;

    if (DGifSlurp(fGIF) != GIF_OK)
    {
        DGifCloseFile(fGIF, nullptr);
        fGIF = nullptr;
    }
    fCurrIndex = -1;
    fLastDrawIndex = -1;
    fPaintingColor = SkPackARGB32(0, 0, 0, 0);
}

SkGIFMovie::~SkGIFMovie()
{
    if (fGIF)
        DGifCloseFile(fGIF, nullptr);
}

static SkMSec savedimage_duration(const SavedImage* image)
{
    for (int j = 0; j < image->ExtensionBlockCount; j++)
    {
        if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE)
        {
            SkASSERT(image->ExtensionBlocks[j].ByteCount >= 4);
            const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes;
            return ((b[2] << 8) | b[1]) * 10;
        }
    }
    return 0;
}

bool SkGIFMovie::onGetInfo(Info* info)
{
    if (nullptr == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
        dur += savedimage_duration(&fGIF->SavedImages[i]);

    info->fDuration = dur;
    info->fWidth = fGIF->SWidth;
    info->fHeight = fGIF->SHeight;
    info->fIsOpaque = false;    // how to compute?
    return true;
}

bool SkGIFMovie::onSetTime(SkMSec time)
{
    if (nullptr == fGIF)
        return false;

    SkMSec dur = 0;
    for (int i = 0; i < fGIF->ImageCount; i++)
    {
        dur += savedimage_duration(&fGIF->SavedImages[i]);
        if (dur >= time)
        {
            fCurrIndex = i;
            return fLastDrawIndex != fCurrIndex;
        }
    }
    fCurrIndex = fGIF->ImageCount - 1;
    return true;
}

static void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap,
                     int transparent, int width)
{
    for (; width > 0; width--, src++, dst++) {
        if (*src != transparent && *src < cmap->ColorCount) {
            const GifColorType& col = cmap->Colors[*src];
            *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue);
        }
    }
}

#if GIFLIB_MAJOR < 5
static void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src,
                               const ColorMapObject* cmap, int transparent, int copyWidth,
                               int copyHeight, const GifImageDesc& imageDesc, int rowStep,
                               int startRow)
{
    int row;
    // every 'rowStep'th row, starting with row 'startRow'
    for (row = startRow; row < copyHeight; row += rowStep) {
        uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row);
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += imageDesc.Width;
    }

    // pad for rest height
    src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep);
}

static void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                          int transparent)
{
    int width = bm->width();
    int height = bm->height();
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    // deinterlace
    const unsigned char* src = (unsigned char*)frame->RasterBits;

    // group 1 - every 8th row, starting with row 0
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0);

    // group 2 - every 8th row, starting with row 4
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4);

    // group 3 - every 4th row, starting with row 2
    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2);

    copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1);
}
#endif

static void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap,
                       int transparent)
{
    int width = bm->width();
    int height = bm->height();
    const unsigned char* src = (unsigned char*)frame->RasterBits;
    uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top);
    GifWord copyWidth = frame->ImageDesc.Width;
    if (frame->ImageDesc.Left + copyWidth > width) {
        copyWidth = width - frame->ImageDesc.Left;
    }

    GifWord copyHeight = frame->ImageDesc.Height;
    if (frame->ImageDesc.Top + copyHeight > height) {
        copyHeight = height - frame->ImageDesc.Top;
    }

    for (; copyHeight > 0; copyHeight--) {
        copyLine(dst, src, cmap, transparent, copyWidth);
        src += frame->ImageDesc.Width;
        dst += width;
    }
}

static void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height,
                     uint32_t col)
{
    int bmWidth = bm->width();
    int bmHeight = bm->height();
    uint32_t* dst = bm->getAddr32(left, top);
    GifWord copyWidth = width;
    if (left + copyWidth > bmWidth) {
        copyWidth = bmWidth - left;
    }

    GifWord copyHeight = height;
    if (top + copyHeight > bmHeight) {
        copyHeight = bmHeight - top;
    }

    for (; copyHeight > 0; copyHeight--) {
        sk_memset32(dst, col, copyWidth);
        dst += bmWidth;
    }
}

static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap)
{
    int transparent = -1;

    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            bool has_transparency = ((eb->Bytes[0] & 1) == 1);
            if (has_transparency) {
                transparent = (unsigned char)eb->Bytes[3];
            }
        }
    }

    if (frame->ImageDesc.ColorMap != nullptr) {
        // use local color table
        cmap = frame->ImageDesc.ColorMap;
    }

    if (cmap == nullptr || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
        SkDEBUGFAIL("bad colortable setup");
        return;
    }

#if GIFLIB_MAJOR < 5
    // before GIFLIB 5, de-interlacing wasn't done by library at load time
    if (frame->ImageDesc.Interlace) {
        blitInterlace(bm, frame, cmap, transparent);
        return;
    }
#endif

    blitNormal(bm, frame, cmap, transparent);
}

static bool checkIfWillBeCleared(const SavedImage* frame)
{
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            // check disposal method
            int disposal = ((eb->Bytes[0] >> 2) & 7);
            if (disposal == 2 || disposal == 3) {
                return true;
            }
        }
    }
    return false;
}

static void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal)
{
    *trans = false;
    *disposal = 0;
    for (int i = 0; i < frame->ExtensionBlockCount; ++i) {
        ExtensionBlock* eb = frame->ExtensionBlocks + i;
        if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
            eb->ByteCount == 4) {
            *trans = ((eb->Bytes[0] & 1) == 1);
            *disposal = ((eb->Bytes[0] >> 2) & 7);
        }
    }
}

// return true if area of 'target' is completely covers area of 'covered'
static bool checkIfCover(const SavedImage* target, const SavedImage* covered)
{
    if (target->ImageDesc.Left <= covered->ImageDesc.Left
        && covered->ImageDesc.Left + covered->ImageDesc.Width <=
               target->ImageDesc.Left + target->ImageDesc.Width
        && target->ImageDesc.Top <= covered->ImageDesc.Top
        && covered->ImageDesc.Top + covered->ImageDesc.Height <=
               target->ImageDesc.Top + target->ImageDesc.Height) {
        return true;
    }
    return false;
}

static void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next,
                                 SkBitmap* backup, SkColor color)
{
    // We can skip disposal process if next frame is not transparent
    // and completely covers current area
    bool curTrans;
    int curDisposal;
    getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal);
    bool nextTrans;
    int nextDisposal;
    getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal);
    if ((curDisposal == 2 || curDisposal == 3)
        && (nextTrans || !checkIfCover(next, cur))) {
        switch (curDisposal) {
        // restore to background color
        // -> 'background' means background under this image.
        case 2:
            fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top,
                     cur->ImageDesc.Width, cur->ImageDesc.Height,
                     color);
            break;

        // restore to previous
        case 3:
            bm->swap(*backup);
            break;
        }
    }

    // Save current image if next frame's disposal method == 3
    if (nextDisposal == 3) {
        const uint32_t* src = bm->getAddr32(0, 0);
        uint32_t* dst = backup->getAddr32(0, 0);
        int cnt = bm->width() * bm->height();
        memcpy(dst, src, cnt*sizeof(uint32_t));
    }
}

bool SkGIFMovie::onGetBitmap(SkBitmap* bm)
{
    const GifFileType* gif = fGIF;
    if (nullptr == gif)
        return false;

    if (gif->ImageCount < 1) {
        return false;
    }

    const int width = gif->SWidth;
    const int height = gif->SHeight;
    if (width <= 0 || height <= 0) {
        return false;
    }

    // no need to draw
    if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) {
        return true;
    }

    int startIndex = fLastDrawIndex + 1;
    if (fLastDrawIndex < 0 || !bm->readyToDraw()) {
        // first time

        startIndex = 0;

        // create bitmap
        if (!bm->tryAllocN32Pixels(width, height)) {
            return false;
        }
        // create bitmap for backup
        if (!fBackup.tryAllocN32Pixels(width, height)) {
            return false;
        }
    } else if (startIndex > fCurrIndex) {
        // rewind to 1st frame for repeat
        startIndex = 0;
    }

    int lastIndex = fCurrIndex;
    if (lastIndex < 0) {
        // first time
        lastIndex = 0;
    } else if (lastIndex > fGIF->ImageCount - 1) {
        // this block must not be reached.
        lastIndex = fGIF->ImageCount - 1;
    }

    SkColor bgColor = SkPackARGB32(0, 0, 0, 0);
    if (gif->SColorMap != nullptr) {
        const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor];
        bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue);
    }

    // draw each frames - not intelligent way
    for (int i = startIndex; i <= lastIndex; i++) {
        const SavedImage* cur = &fGIF->SavedImages[i];
        if (i == 0) {
            bool trans;
            int disposal;
            getTransparencyAndDisposalMethod(cur, &trans, &disposal);
            if (!trans && gif->SColorMap != nullptr) {
                fPaintingColor = bgColor;
            } else {
                fPaintingColor = SkColorSetARGB(0, 0, 0, 0);
            }

            bm->eraseColor(fPaintingColor);
            fBackup.eraseColor(fPaintingColor);
        } else {
            // Dispose previous frame before move to next frame.
            const SavedImage* prev = &fGIF->SavedImages[i-1];
            disposeFrameIfNeeded(bm, prev, cur, &fBackup, fPaintingColor);
        }

        // Draw frame
        // We can skip this process if this index is not last and disposal
        // method == 2 or method == 3
        if (i == lastIndex || !checkIfWillBeCleared(cur)) {
            drawFrame(bm, cur, gif->SColorMap);
        }
    }

    // save index
    fLastDrawIndex = lastIndex;
    return true;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkTRegistry.h"

SkMovie* Factory(SkStreamRewindable* stream) {
    char buf[GIF_STAMP_LEN];
    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
            // must rewind here, since our construct wants to re-read the data
            stream->rewind();
            return new SkGIFMovie(stream);
        }
    }
    return nullptr;
}

static SkTRegistry<SkMovie*(*)(SkStreamRewindable*)> gReg(Factory);
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bwtree_index.cpp
//
// Identification: src/backend/index/bwtree_index.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "index/bwtree_index.h"

#include "common/logger.h"
#include "index/index_key.h"
#include "index/scan_optimizer.h"
#include "statistics/stats_aggregator.h"
#include "storage/tuple.h"

namespace peloton {
namespace index {

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::BWTreeIndex(IndexMetadata *metadata)
    :  // Base class
      Index{metadata},
      // Key "less than" relation comparator
      comparator{},
      // Key equality checker
      equals{},
      // Key hash function
      hash_func{},
      // NOTE: These two arguments need to be constructed in advance
      // and do not have trivial constructor
      //
      // NOTE 2: We set the first parameter to false to disable automatic GC
      //
      container{false, comparator, equals, hash_func} {
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::~BWTreeIndex() {}

/*
 * InsertEntry() - insert a key-value pair into the map
 *
 * If the key value pair already exists in the map, just return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::InsertEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool ret = container.Insert(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * DeleteEntry() - Removes a key-value pair
 *
 * If the key-value pair does not exists yet in the map return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::DeleteEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);
  size_t delete_count = 0;

  // In Delete() since we just use the value for comparison (i.e. read-only)
  // it is unnecessary for us to allocate memory
  bool ret = container.Delete(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexDeletes(
        delete_count, metadata);
  }
  return ret;
}

BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::CondInsertEntry(
    const storage::Tuple *key, ItemPointer *value,
    std::function<bool(const void *)> predicate) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool predicate_satisfied = false;

  // This function will complete them in one step
  // predicate will be set to nullptr if the predicate
  // returns true for some value
  bool ret = container.ConditionalInsert(index_key, value, predicate,
                                         &predicate_satisfied);

  // If predicate is not satisfied then we know insertion successes
  if (predicate_satisfied == false) {
    // So it should always succeed?
    assert(ret == true);
  } else {
    assert(ret == false);
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * Scan() - Scans a range inside the index using index scan optimizer
 *
 * The scan optimizer specifies whether a scan is point query, full scan
 * or interval scan. For all of these cases the corresponding functions from
 * the index is called, and all elements are returned in result vector
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::Scan(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    ScanDirectionType scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p) {
  // This is a hack - we do not support backward scan
  if (scan_direction == SCAN_DIRECTION_TYPE_INVALID) {
    throw Exception("Invalid scan direction \n");
  }

  LOG_TRACE("Scan() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_key_p);

    // Note: We could call ScanKey() to achieve better modularity
    // (slightly less code), but since ScanKey() is a virtual function
    // this would induce an overhead for point query, which must be highly
    // optimized and super fast
    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

/*
 * ScanLimit() - Scan the index with predicate and limit/offset
 *
 * This function scans the index using the given index optimizer's low key and
 * high key. In addition to merely doing the scan, it checks scan direction
 * and uses either begin() or end() iterator to scan the index, and stops
 * after offset + limit elements are scanned, and limit elements are finally
 * returned
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanLimit(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    ScanDirectionType scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p,
    uint64_t limit,
    uint64_t offset) {
  LOG_TRACE("ScanLimit() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if(csp_p->IsPointQuery() == false && \
     limit == 1 && \
     offset == 0 && \
     scan_direction == SCAN_DIRECTION_TYPE_FORWARD) {

  }
/*
  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_tuple_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_tuple_key_p);

    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
*/

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanAllKeys(std::vector<ValueType> &result) {
  auto it = container.Begin();

  // scan all entries
  while (it.IsEnd() == false) {
    result.push_back(it->second);
    it++;
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanKey(const storage::Tuple *key,
                                std::vector<ValueType> &result) {
  KeyType index_key;
  index_key.SetFromKey(key);

  // This function in BwTree fills a given vector
  container.GetValue(index_key, result);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
std::string BWTREE_INDEX_TYPE::GetTypeName() const { return "BWTree"; }

// IMPORTANT: Make sure you don't exceed CompactIntegerKey_MAX_SLOTS

template class BWTreeIndex<CompactIntsKey<1>, ItemPointer *,
                           CompactIntsComparator<1>,
                           CompactIntsEqualityChecker<1>, CompactIntsHasher<1>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<2>, ItemPointer *,
                           CompactIntsComparator<2>,
                           CompactIntsEqualityChecker<2>, CompactIntsHasher<2>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<3>, ItemPointer *,
                           CompactIntsComparator<3>,
                           CompactIntsEqualityChecker<3>, CompactIntsHasher<3>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<4>, ItemPointer *,
                           CompactIntsComparator<4>,
                           CompactIntsEqualityChecker<4>, CompactIntsHasher<4>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Generic key
template class BWTreeIndex<GenericKey<4>, ItemPointer *,
                           FastGenericComparator<4>, GenericEqualityChecker<4>,
                           GenericHasher<4>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<8>, ItemPointer *,
                           FastGenericComparator<8>, GenericEqualityChecker<8>,
                           GenericHasher<8>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<16>, ItemPointer *,
                           FastGenericComparator<16>,
                           GenericEqualityChecker<16>, GenericHasher<16>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<64>, ItemPointer *,
                           FastGenericComparator<64>,
                           GenericEqualityChecker<64>, GenericHasher<64>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<256>, ItemPointer *,
                           FastGenericComparator<256>,
                           GenericEqualityChecker<256>, GenericHasher<256>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Tuple key
template class BWTreeIndex<TupleKey, ItemPointer *, TupleKeyComparator,
                           TupleKeyEqualityChecker, TupleKeyHasher,
                           ItemPointerComparator, ItemPointerHashFunc>;

}  // End index namespace
}  // End peloton namespace
<commit_msg>Finish ScanLimit()<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bwtree_index.cpp
//
// Identification: src/backend/index/bwtree_index.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "index/bwtree_index.h"

#include "common/logger.h"
#include "index/index_key.h"
#include "index/scan_optimizer.h"
#include "statistics/stats_aggregator.h"
#include "storage/tuple.h"

namespace peloton {
namespace index {

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::BWTreeIndex(IndexMetadata *metadata)
    :  // Base class
      Index{metadata},
      // Key "less than" relation comparator
      comparator{},
      // Key equality checker
      equals{},
      // Key hash function
      hash_func{},
      // NOTE: These two arguments need to be constructed in advance
      // and do not have trivial constructor
      //
      // NOTE 2: We set the first parameter to false to disable automatic GC
      //
      container{false, comparator, equals, hash_func} {
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::~BWTreeIndex() {}

/*
 * InsertEntry() - insert a key-value pair into the map
 *
 * If the key value pair already exists in the map, just return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::InsertEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool ret = container.Insert(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * DeleteEntry() - Removes a key-value pair
 *
 * If the key-value pair does not exists yet in the map return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::DeleteEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);
  size_t delete_count = 0;

  // In Delete() since we just use the value for comparison (i.e. read-only)
  // it is unnecessary for us to allocate memory
  bool ret = container.Delete(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexDeletes(
        delete_count, metadata);
  }
  return ret;
}

BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::CondInsertEntry(
    const storage::Tuple *key, ItemPointer *value,
    std::function<bool(const void *)> predicate) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool predicate_satisfied = false;

  // This function will complete them in one step
  // predicate will be set to nullptr if the predicate
  // returns true for some value
  bool ret = container.ConditionalInsert(index_key, value, predicate,
                                         &predicate_satisfied);

  // If predicate is not satisfied then we know insertion successes
  if (predicate_satisfied == false) {
    // So it should always succeed?
    assert(ret == true);
  } else {
    assert(ret == false);
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * Scan() - Scans a range inside the index using index scan optimizer
 *
 * The scan optimizer specifies whether a scan is point query, full scan
 * or interval scan. For all of these cases the corresponding functions from
 * the index is called, and all elements are returned in result vector
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::Scan(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    ScanDirectionType scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p) {
  // This is a hack - we do not support backward scan
  if (scan_direction == SCAN_DIRECTION_TYPE_INVALID) {
    throw Exception("Invalid scan direction \n");
  }

  LOG_TRACE("Scan() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_key_p);

    // Note: We could call ScanKey() to achieve better modularity
    // (slightly less code), but since ScanKey() is a virtual function
    // this would induce an overhead for point query, which must be highly
    // optimized and super fast
    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

/*
 * ScanLimit() - Scan the index with predicate and limit/offset
 *
 * This function scans the index using the given index optimizer's low key and
 * high key. In addition to merely doing the scan, it checks scan direction
 * and uses either begin() or end() iterator to scan the index, and stops
 * after offset + limit elements are scanned, and limit elements are finally
 * returned
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanLimit(
    const std::vector<type::Value> &value_list,
    const std::vector<oid_t> &tuple_column_id_list,
    const std::vector<ExpressionType> &expr_list,
    ScanDirectionType scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p,
    uint64_t limit,
    uint64_t offset) {

  // Only work with limit == 1 and offset == 0
  // Because that gets translated to "min"
  // But still since we could not access tuples in the table
  // the index just fetches the first qualified key without further checking
  // including checking for non-exact bounds!!!
  if(csp_p->IsPointQuery() == false && \
     limit == 1 && \
     offset == 0 && \
     scan_direction == SCAN_DIRECTION_TYPE_FORWARD) {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("ScanLimit() special case (limit = 1; offset = 0; ASCENDING): %s",
              low_key_p->GetInfo().c_str());

    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    auto scan_itr = container.Begin(index_low_key);
    if((scan_itr.IsEnd() == false) && \
       (container.KeyCmpLessEqual(scan_itr->first, index_high_key))) {

      result.push_back(scan_itr->second);
    }
  } else {
    Scan(value_list,
         tuple_column_id_list,
         expr_list,
         scan_direction,
         result,
         csp_p);
  }

  return;
/*
  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_tuple_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_tuple_key_p);

    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
*/

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanAllKeys(std::vector<ValueType> &result) {
  auto it = container.Begin();

  // scan all entries
  while (it.IsEnd() == false) {
    result.push_back(it->second);
    it++;
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanKey(const storage::Tuple *key,
                                std::vector<ValueType> &result) {
  KeyType index_key;
  index_key.SetFromKey(key);

  // This function in BwTree fills a given vector
  container.GetValue(index_key, result);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
std::string BWTREE_INDEX_TYPE::GetTypeName() const { return "BWTree"; }

// IMPORTANT: Make sure you don't exceed CompactIntegerKey_MAX_SLOTS

template class BWTreeIndex<CompactIntsKey<1>, ItemPointer *,
                           CompactIntsComparator<1>,
                           CompactIntsEqualityChecker<1>, CompactIntsHasher<1>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<2>, ItemPointer *,
                           CompactIntsComparator<2>,
                           CompactIntsEqualityChecker<2>, CompactIntsHasher<2>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<3>, ItemPointer *,
                           CompactIntsComparator<3>,
                           CompactIntsEqualityChecker<3>, CompactIntsHasher<3>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<4>, ItemPointer *,
                           CompactIntsComparator<4>,
                           CompactIntsEqualityChecker<4>, CompactIntsHasher<4>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Generic key
template class BWTreeIndex<GenericKey<4>, ItemPointer *,
                           FastGenericComparator<4>, GenericEqualityChecker<4>,
                           GenericHasher<4>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<8>, ItemPointer *,
                           FastGenericComparator<8>, GenericEqualityChecker<8>,
                           GenericHasher<8>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<16>, ItemPointer *,
                           FastGenericComparator<16>,
                           GenericEqualityChecker<16>, GenericHasher<16>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<64>, ItemPointer *,
                           FastGenericComparator<64>,
                           GenericEqualityChecker<64>, GenericHasher<64>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<256>, ItemPointer *,
                           FastGenericComparator<256>,
                           GenericEqualityChecker<256>, GenericHasher<256>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Tuple key
template class BWTreeIndex<TupleKey, ItemPointer *, TupleKeyComparator,
                           TupleKeyEqualityChecker, TupleKeyHasher,
                           ItemPointerComparator, ItemPointerHashFunc>;

}  // End index namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>#ifndef VAST_DETAIL_RANGE_HPP
#define VAST_DETAIL_RANGE_HPP

#include "vast/detail/assert.hpp"
#include "vast/detail/iterator.hpp"

namespace vast {
namespace detail {

template <typename Derived>
class range {
  Derived& derived() {
    return static_cast<Derived&>(*this);
  }

  Derived const& derived() const {
    return static_cast<Derived const&>(*this);
  }

public:
  explicit operator bool() const {
    return !empty();
  }

  bool operator!() const {
    return empty();
  }

  bool empty() const {
    return derived().begin() == derived().end();
  }
};

template <typename Range>
class range_iterator
  : public iterator_facade<
      range_iterator<Range>,
      decltype(std::declval<Range>().dereference()),
      std::forward_iterator_tag
    > {
  friend Range;
  friend iterator_access;

public:
  range_iterator() = default;

private:
  explicit range_iterator(Range& rng) : rng_{&rng} {
  }

  bool equals(range_iterator const& other) const {
    return rng_ == other.rng_;
  }

  void increment() {
    VAST_ASSERT(rng_);
    if (!rng_->increment())
      rng_ = nullptr;
  }

  auto dereference() const -> decltype(std::declval<Range>().dereference()) {
    return rng_->dereference();
  }

  Range* rng_ = nullptr;
};

template <typename Derived>
class range_facade : public range<range_facade<Derived>> {
public:
  using iterator = range_iterator<range_facade<Derived>>;
  using const_iterator = iterator;

  iterator begin() const {
    return iterator{const_cast<range_facade&>(*this)};
  }

  iterator end() const {
    return iterator{};
  }

private:
  friend iterator;

  bool increment() {
    return static_cast<Derived*>(this)->next();
  }

#ifdef VAST_GCC
// FIXME: The range_iterator uses the range (composition), but in the
// definition of range_iterator, the call to
// decltype(std::declval<Range>().dereference()) fails because the range has
// not yet been befriended.
//
// As a workaround, we just make this method public. Clang doesn't complain.
public:
#endif
  template <typename Hack = Derived>
  auto dereference() const
    -> decltype(std::declval<Hack>().state()) {
    static_assert(std::is_same<Hack, Derived>::value, ":-P");
    return static_cast<Derived const*>(this)->state();
  }
};

template <typename ForwardIterator>
class iterator_range : public range<iterator_range<ForwardIterator>> {
public:
  template <typename Iterator>
  iterator_range(Iterator begin, Iterator end)
    : begin_{begin}, end_{end} {
  }

  ForwardIterator begin() const {
    return begin_;
  }

  ForwardIterator end() const {
    return end_;
  }

private:
  ForwardIterator begin_;
  ForwardIterator end_;
};

} // namespace detail
} // namespace vast

#endif
<commit_msg>Simplify range utilities<commit_after>#ifndef VAST_DETAIL_RANGE_HPP
#define VAST_DETAIL_RANGE_HPP

#include "vast/detail/assert.hpp"
#include "vast/detail/iterator.hpp"

namespace vast {
namespace detail {

template <typename Derived>
class range {
public:
  explicit operator bool() const {
    return !empty();
  }

  bool operator!() const {
    return empty();
  }

  bool empty() const {
    auto d = static_cast<Derived const*>(this);
    return d->begin() == d->end();
  }
};

template <typename Range>
class range_iterator
  : public iterator_facade<
      range_iterator<Range>,
      decltype(std::declval<Range>().dereference()),
      std::forward_iterator_tag
    > {
  friend Range;
  friend iterator_access;

public:
  range_iterator() = default;

private:
  explicit range_iterator(Range& rng) : rng_{&rng} {
  }

  bool equals(range_iterator const& other) const {
    return rng_ == other.rng_;
  }

  void increment() {
    VAST_ASSERT(rng_);
    if (!rng_->increment())
      rng_ = nullptr;
  }

  decltype(auto) dereference() const {
    return rng_->dereference();
  }

  Range* rng_ = nullptr;
};

template <typename Derived>
class range_facade : public range<range_facade<Derived>> {
public:
  using iterator = range_iterator<range_facade<Derived>>;
  using const_iterator = iterator;

  iterator begin() const {
    return iterator{const_cast<range_facade&>(*this)};
  }

  iterator end() const {
    return iterator{};
  }

private:
  friend iterator;

  bool increment() {
    return static_cast<Derived*>(this)->next();
  }

  decltype(auto) dereference() const {
    return static_cast<Derived const*>(this)->state();
  }
};

template <typename ForwardIterator>
class iterator_range : public range<iterator_range<ForwardIterator>> {
public:
  template <typename Iterator>
  iterator_range(Iterator begin, Iterator end)
    : begin_{begin}, end_{end} {
  }

  ForwardIterator begin() const {
    return begin_;
  }

  ForwardIterator end() const {
    return end_;
  }

private:
  ForwardIterator begin_;
  ForwardIterator end_;
};

} // namespace detail
} // namespace vast

#endif
<|endoftext|>


<commit_before><commit_msg>Fix a crash when painting is disabled. We would be passed NULL and it wasn't checking the correct value for this case. Review URL: http://codereview.chromium.org/8767<commit_after><|endoftext|>