<commit_before>/*
* The MIT License (MIT)
*
* Copyright (c) Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/

/**
  Test JIT code emission.
*/

#include "stdafx.h"
#include "catch.hpp"
#include "testing_util.h"
#include <Python.h>
#include <frameobject.h>
#include <util.h>
#include <pyjit.h>

class EmissionTest {
private:
    py_ptr<PyCodeObject> m_code;
    py_ptr<PyJittedCode> m_jittedcode;

    PyObject* run() {
        auto sysModule = PyObject_ptr(PyImport_ImportModule("sys"));
        auto globals = PyObject_ptr(PyDict_New());
        auto builtins = PyThreadState_GET()->interp->builtins;
        PyDict_SetItemString(globals.get(), "__builtins__", builtins);
        PyDict_SetItemString(globals.get(), "sys", sysModule.get());

        // Don't DECREF as frames are recycled.
        auto frame = PyFrame_New(PyThreadState_Get(), m_code.get(), globals.get(), PyObject_ptr(PyDict_New()).get());

        auto res = m_jittedcode->j_evalfunc(m_jittedcode->j_evalstate, frame);

        return res;
    }

public:
    EmissionTest(const char *code) {
        m_code.reset(CompileCode(code));
        if (m_code.get() == nullptr) {
            FAIL("failed to compile code");
        }
        m_jittedcode.reset(JitCompile(m_code.get()));
        if (m_jittedcode.get() == nullptr) {
            FAIL("failed to JIT code");
        }
    }

    std::string returns() {
        auto res = PyObject_ptr(run());
        REQUIRE(res.get() != nullptr);
        REQUIRE(!PyErr_Occurred());

        auto repr = PyUnicode_AsUTF8(PyObject_Repr(res.get()));
        auto tstate = PyThreadState_GET();
        REQUIRE(tstate->exc_value == nullptr);
        REQUIRE(tstate->exc_traceback == nullptr);
        if (tstate->exc_type != nullptr) {
            REQUIRE(tstate->exc_type == Py_None);
        }

        return std::string(repr);
    }

    PyObject* raises() {
        auto res = run();
        REQUIRE(res == nullptr);
        auto excType = PyErr_Occurred();
        PyErr_Clear();
        return excType;
    }
};

TEST_CASE("General list unpacking", "[list][BUILD_LIST_UNPACK][emission]") {
    SECTION("common case") {
        auto t = EmissionTest("def f(): return [1, *[2], 3]");
        REQUIRE(t.returns() == "[1, 2, 3]");
    }

    SECTION("unpacking a non-iterable") {
        auto t = EmissionTest("def f(): return [1, *2, 3]");
        REQUIRE(t.raises() == PyExc_TypeError);
    }
}<commit_msg>Add failing tests for BUILD_TUPLE_UNPACK<commit_after>/*
* The MIT License (MIT)
*
* Copyright (c) Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/

/**
  Test JIT code emission.
*/

#include "stdafx.h"
#include "catch.hpp"
#include "testing_util.h"
#include <Python.h>
#include <frameobject.h>
#include <util.h>
#include <pyjit.h>

class EmissionTest {
private:
    py_ptr<PyCodeObject> m_code;
    py_ptr<PyJittedCode> m_jittedcode;

    PyObject* run() {
        auto sysModule = PyObject_ptr(PyImport_ImportModule("sys"));
        auto globals = PyObject_ptr(PyDict_New());
        auto builtins = PyThreadState_GET()->interp->builtins;
        PyDict_SetItemString(globals.get(), "__builtins__", builtins);
        PyDict_SetItemString(globals.get(), "sys", sysModule.get());

        // Don't DECREF as frames are recycled.
        auto frame = PyFrame_New(PyThreadState_Get(), m_code.get(), globals.get(), PyObject_ptr(PyDict_New()).get());

        auto res = m_jittedcode->j_evalfunc(m_jittedcode->j_evalstate, frame);

        return res;
    }

public:
    EmissionTest(const char *code) {
        m_code.reset(CompileCode(code));
        if (m_code.get() == nullptr) {
            FAIL("failed to compile code");
        }
        m_jittedcode.reset(JitCompile(m_code.get()));
        if (m_jittedcode.get() == nullptr) {
            FAIL("failed to JIT code");
        }
    }

    std::string returns() {
        auto res = PyObject_ptr(run());
        REQUIRE(res.get() != nullptr);
        REQUIRE(!PyErr_Occurred());

        auto repr = PyUnicode_AsUTF8(PyObject_Repr(res.get()));
        auto tstate = PyThreadState_GET();
        REQUIRE(tstate->exc_value == nullptr);
        REQUIRE(tstate->exc_traceback == nullptr);
        if (tstate->exc_type != nullptr) {
            REQUIRE(tstate->exc_type == Py_None);
        }

        return std::string(repr);
    }

    PyObject* raises() {
        auto res = run();
        REQUIRE(res == nullptr);
        auto excType = PyErr_Occurred();
        PyErr_Clear();
        return excType;
    }
};

TEST_CASE("General list unpacking", "[list][BUILD_LIST_UNPACK][emission]") {
    SECTION("common case") {
        auto t = EmissionTest("def f(): return [1, *[2], 3]");
        CHECK(t.returns() == "[1, 2, 3]");
    }

    SECTION("unpacking a non-iterable") {
        auto t = EmissionTest("def f(): return [1, *2, 3]");
        CHECK(t.raises() == PyExc_TypeError);
    }
}

TEST_CASE("General tuple unpacking", "[tuple][BUILD_TUPLE_UNPACK][emission]") {
    SECTION("common case") {
        auto t = EmissionTest("def f(): return (1, *(2,), 3)");
        CHECK(t.returns() == "(1, 2, 3)");
    }

    SECTION("unpacking a non-iterable") {
        auto t = EmissionTest("def f(): return (1, *2, 3)");
        CHECK(t.raises() == PyExc_TypeError);
    }
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    TiffVolumeConverter.h
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include <cstring>
#include "boost/cstdint.hpp"
#ifndef TUVOK_NO_IO
# include "3rdParty/tiff/tiffio.h"
#else
  struct TIFF;
#endif
#include "TiffVolumeConverter.h"
#include "../StdTuvokDefines.h"
#include "../Controller/Controller.h"
#include "../Basics/SysTools.h"

#ifdef __GNUC__
# define _malloc __attribute__((malloc))
#else
# define _malloc /* nothing */
#endif

static void tv_dimensions(TIFF *, size_t dims[3]);
_malloc static BYTE* tv_read_slice(TIFF *);

TiffVolumeConverter::TiffVolumeConverter()
{
  m_vConverterDesc = "TIFF Volume (Image stack)";
#ifndef TUVOK_NO_IO
  m_vSupportedExt.push_back("OME.TIF");
  m_vSupportedExt.push_back("OME.TIFF");
  m_vSupportedExt.push_back("TIF");
  m_vSupportedExt.push_back("TIFF");
#endif
}

// converts a TiffVolume to a `raw' file.  We'll read through the TIFF
// slice-by-slice, copying each slice to the raw file.
bool
TiffVolumeConverter::ConvertToRAW(const std::string& strSourceFilename,
                                  const std::string& strTempDir,
                                  bool, UINT64& iHeaderSkip,
                                  UINT64& iComponentSize,
                                  UINT64& iComponentCount,
                                  bool& bConvertEndianess, bool& bSigned,
                                  bool& bIsFloat, UINTVECTOR3& vVolumeSize,
                                  FLOATVECTOR3& vVolumeAspect,
                                  std::string& strTitle,
                                  UVFTables::ElementSemanticTable& eType,
                                  std::string& strIntermediateFile,
                                  bool& bDeleteIntermediateFile)
{
#ifndef TUVOK_NO_IO
  MESSAGE("Attempting to convert TiffVolume: %s", strSourceFilename.c_str());

  TIFF *tif = TIFFOpen(strSourceFilename.c_str(), "r");
  if(tif == NULL) {
    T_ERROR("Could not open %s", strSourceFilename.c_str());
    return false;
  }

  // Get the dimensions of the volume.
  {
    size_t dims[3];
    tv_dimensions(tif, dims);
    vVolumeSize[0] = UINT32(dims[0]);
    vVolumeSize[1] = UINT32(dims[1]);
    vVolumeSize[2] = UINT32(dims[2]);
    MESSAGE("TiffVolume dimensions: %ux%ux%u", UINT32(dims[0]), UINT32(dims[1]), UINT32(dims[2]));
    if(dims[2] <= 1) {
      T_ERROR("TIFF is not a volume; use "
            "`Load Dataset from Directory' instead!");
      TIFFClose(tif);
      return false;
    }
  }
  iHeaderSkip = 0;

  // read the number of bits per component from the tiff tag.
  {
    boost::uint16_t bits_per_sample;
    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
    iComponentSize = bits_per_sample;
    MESSAGE("%ld bits per component.", iComponentSize);
  }
  // likewise for the number of components / pixel.
  {
    boost::uint16_t components;
    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &components);
    iComponentCount = components;
    MESSAGE("%ld component%s.", iComponentCount,
                (components == 1) ? "" : "s");
  }
  // IIRC libtiff handles all the endian issues for us.
  bConvertEndianess = false;

  // One might consider setting the values below explicitly as bugs, but we're
  // not quite sure where to read these from.  In any case, we don't have any
  // data for which these settings are invalid.
  bSigned = false;
  bIsFloat = false;
  vVolumeAspect[0] = 1;
  vVolumeAspect[1] = 1;
  vVolumeAspect[2] = 1;

  strTitle = "TIFF Volume";
  eType = UVFTables::ES_UNDEFINED;

  // Create an intermediate file to hold the data.
  strIntermediateFile = strTempDir +
                        SysTools::GetFilename(strSourceFilename) + ".binary";
  LargeRAWFile binary(strIntermediateFile);
  binary.Create(iComponentSize/8 * iComponentCount * vVolumeSize.volume());
  if(!binary.IsOpen()) {
    T_ERROR("Could not create binary file %s", strIntermediateFile.c_str());

    TIFFClose(tif);
    return false;
  }
  bDeleteIntermediateFile = true;
  // Populate the intermediate file.  We'll do this slice-by-slice, which isn't
  // exactly kosher in Tuvok -- a slice could technically be larger than
  // INCORESIZE.  But it won't be.
  do {
    BYTE* slice = tv_read_slice(tif);
    if(slice) {
      // assuming 8-bit monochrome data here, which might not always be valid.
      binary.WriteRAW(static_cast<unsigned char*>(slice),
                      vVolumeSize[0]*vVolumeSize[1]*sizeof(BYTE));
      _TIFFfree(slice);
    } else {
      binary.Close();
      binary.Delete();
      TIFFClose(tif);
      return false;
    }
  } while(TIFFReadDirectory(tif));
  binary.Close();

  TIFFClose(tif);
  return true;
#else
  T_ERROR("Tuvok was not built with IO support!");
  return false;
#endif
}

// unimplemented!
bool
TiffVolumeConverter::ConvertToNative(const std::string&,
                                     const std::string&,
                                     UINT64, UINT64,
                                     UINT64, bool,
                                     bool,
                                     UINTVECTOR3,
                                     FLOATVECTOR3,
                                     bool)
{
  return false;
}

// Reads the dimensions of the TIFF volume.  X and Y come from the dimensions
// of the first image in the stack: we assume that this stays constant
// throughout the volume.  Z comes from the number of images in the stack.
static void
tv_dimensions(TIFF *tif, size_t dims[3])
{
#ifndef TUVOK_NO_IO
  UINT32 x,y;
  size_t z=0;

  TIFFSetDirectory(tif, 0);
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x);
  // tiff calls the height "length" for some reason.
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y);
  do {
    ++z;
  } while(TIFFReadDirectory(tif));
  TIFFSetDirectory(tif, 0);

  dims[0] = x;
  dims[1] = y;
  dims[2] = z;
#endif
}

_malloc static BYTE*
tv_read_slice(TIFF *tif)
{
#ifdef TUVOK_NO_IO
  return NULL;
#else
  BYTE *slice;
  UINT32 width;
  UINT32 height;
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);

  MESSAGE("Reading %ux%u TIFF slice.", width, height);
  slice = static_cast<BYTE*>(_TIFFmalloc((width*height) * sizeof(BYTE)));
  if(slice == NULL) {
    T_ERROR("TIFFmalloc failed.");
    return NULL;
  }
  const tstrip_t n_strips = TIFFNumberOfStrips(tif);
  {
    BYTE *data = slice;
    tdata_t buf = static_cast<tdata_t>(_TIFFmalloc(TIFFStripSize(tif)));
    for(tstrip_t s=0; s < n_strips; ++s) {
      /// @todo FIXME: don't assume the strip is raw; could be encoded.
      /// There's a `compression scheme' tag which probably details this.
      tsize_t n_bytes = TIFFReadRawStrip(tif, s, buf,
                                         static_cast<tsize_t>(-1));
      std::memcpy(data, buf, n_bytes);
      data += TIFFStripSize(tif);
    }
    _TIFFfree(buf);
  }

  return slice;
#endif
}
<commit_msg>Fix (null) in debug message.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    TiffVolumeConverter.h
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include <cstring>
#include "boost/cstdint.hpp"
#ifndef TUVOK_NO_IO
# include "3rdParty/tiff/tiffio.h"
#else
  struct TIFF;
#endif
#include "TiffVolumeConverter.h"
#include "../StdTuvokDefines.h"
#include "../Controller/Controller.h"
#include "../Basics/SysTools.h"

#ifdef __GNUC__
# define _malloc __attribute__((malloc))
#else
# define _malloc /* nothing */
#endif

static void tv_dimensions(TIFF *, size_t dims[3]);
_malloc static BYTE* tv_read_slice(TIFF *);

TiffVolumeConverter::TiffVolumeConverter()
{
  m_vConverterDesc = "TIFF Volume (Image stack)";
#ifndef TUVOK_NO_IO
  m_vSupportedExt.push_back("OME.TIF");
  m_vSupportedExt.push_back("OME.TIFF");
  m_vSupportedExt.push_back("TIF");
  m_vSupportedExt.push_back("TIFF");
#endif
}

// converts a TiffVolume to a `raw' file.  We'll read through the TIFF
// slice-by-slice, copying each slice to the raw file.
bool
TiffVolumeConverter::ConvertToRAW(const std::string& strSourceFilename,
                                  const std::string& strTempDir,
                                  bool, UINT64& iHeaderSkip,
                                  UINT64& iComponentSize,
                                  UINT64& iComponentCount,
                                  bool& bConvertEndianess, bool& bSigned,
                                  bool& bIsFloat, UINTVECTOR3& vVolumeSize,
                                  FLOATVECTOR3& vVolumeAspect,
                                  std::string& strTitle,
                                  UVFTables::ElementSemanticTable& eType,
                                  std::string& strIntermediateFile,
                                  bool& bDeleteIntermediateFile)
{
#ifndef TUVOK_NO_IO
  MESSAGE("Attempting to convert TiffVolume: %s", strSourceFilename.c_str());

  TIFF *tif = TIFFOpen(strSourceFilename.c_str(), "r");
  if(tif == NULL) {
    T_ERROR("Could not open %s", strSourceFilename.c_str());
    return false;
  }

  // Get the dimensions of the volume.
  {
    size_t dims[3];
    tv_dimensions(tif, dims);
    vVolumeSize[0] = UINT32(dims[0]);
    vVolumeSize[1] = UINT32(dims[1]);
    vVolumeSize[2] = UINT32(dims[2]);
    MESSAGE("TiffVolume dimensions: %ux%ux%u", UINT32(dims[0]), UINT32(dims[1]), UINT32(dims[2]));
    if(dims[2] <= 1) {
      T_ERROR("TIFF is not a volume; use "
            "`Load Dataset from Directory' instead!");
      TIFFClose(tif);
      return false;
    }
  }
  iHeaderSkip = 0;

  // read the number of bits per component from the tiff tag.
  {
    boost::uint16_t bits_per_sample;
    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
    iComponentSize = bits_per_sample;
    MESSAGE("%ld bits per component.", iComponentSize);
  }
  // likewise for the number of components / pixel.
  {
    boost::uint16_t components;
    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &components);
    iComponentCount = components;
    {
      std::ostringstream com;
      com << iComponentCount << "component";
      if(components > 1) { com << "s"; }
      com << ".";
      MESSAGE("%s", com.str().c_str());
    }
  }
  // IIRC libtiff handles all the endian issues for us.
  bConvertEndianess = false;

  // One might consider setting the values below explicitly as bugs, but we're
  // not quite sure where to read these from.  In any case, we don't have any
  // data for which these settings are invalid.
  bSigned = false;
  bIsFloat = false;
  vVolumeAspect[0] = 1;
  vVolumeAspect[1] = 1;
  vVolumeAspect[2] = 1;

  strTitle = "TIFF Volume";
  eType = UVFTables::ES_UNDEFINED;

  // Create an intermediate file to hold the data.
  strIntermediateFile = strTempDir +
                        SysTools::GetFilename(strSourceFilename) + ".binary";
  LargeRAWFile binary(strIntermediateFile);
  binary.Create(iComponentSize/8 * iComponentCount * vVolumeSize.volume());
  if(!binary.IsOpen()) {
    T_ERROR("Could not create binary file %s", strIntermediateFile.c_str());

    TIFFClose(tif);
    return false;
  }
  bDeleteIntermediateFile = true;
  // Populate the intermediate file.  We'll do this slice-by-slice, which isn't
  // exactly kosher in Tuvok -- a slice could technically be larger than
  // INCORESIZE.  But it won't be.
  do {
    BYTE* slice = tv_read_slice(tif);
    if(slice) {
      // assuming 8-bit monochrome data here, which might not always be valid.
      binary.WriteRAW(static_cast<unsigned char*>(slice),
                      vVolumeSize[0]*vVolumeSize[1]*sizeof(BYTE));
      _TIFFfree(slice);
    } else {
      binary.Close();
      binary.Delete();
      TIFFClose(tif);
      return false;
    }
  } while(TIFFReadDirectory(tif));
  binary.Close();

  TIFFClose(tif);
  return true;
#else
  T_ERROR("Tuvok was not built with IO support!");
  return false;
#endif
}

// unimplemented!
bool
TiffVolumeConverter::ConvertToNative(const std::string&,
                                     const std::string&,
                                     UINT64, UINT64,
                                     UINT64, bool,
                                     bool,
                                     UINTVECTOR3,
                                     FLOATVECTOR3,
                                     bool)
{
  return false;
}

// Reads the dimensions of the TIFF volume.  X and Y come from the dimensions
// of the first image in the stack: we assume that this stays constant
// throughout the volume.  Z comes from the number of images in the stack.
static void
tv_dimensions(TIFF *tif, size_t dims[3])
{
#ifndef TUVOK_NO_IO
  UINT32 x,y;
  size_t z=0;

  TIFFSetDirectory(tif, 0);
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x);
  // tiff calls the height "length" for some reason.
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y);
  do {
    ++z;
  } while(TIFFReadDirectory(tif));
  TIFFSetDirectory(tif, 0);

  dims[0] = x;
  dims[1] = y;
  dims[2] = z;
#endif
}

_malloc static BYTE*
tv_read_slice(TIFF *tif)
{
#ifdef TUVOK_NO_IO
  return NULL;
#else
  BYTE *slice;
  UINT32 width;
  UINT32 height;
  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);

  MESSAGE("Reading %ux%u TIFF slice.", width, height);
  slice = static_cast<BYTE*>(_TIFFmalloc((width*height) * sizeof(BYTE)));
  if(slice == NULL) {
    T_ERROR("TIFFmalloc failed.");
    return NULL;
  }
  const tstrip_t n_strips = TIFFNumberOfStrips(tif);
  {
    BYTE *data = slice;
    tdata_t buf = static_cast<tdata_t>(_TIFFmalloc(TIFFStripSize(tif)));
    for(tstrip_t s=0; s < n_strips; ++s) {
      /// @todo FIXME: don't assume the strip is raw; could be encoded.
      /// There's a `compression scheme' tag which probably details this.
      tsize_t n_bytes = TIFFReadRawStrip(tif, s, buf,
                                         static_cast<tsize_t>(-1));
      std::memcpy(data, buf, n_bytes);
      data += TIFFStripSize(tif);
    }
    _TIFFfree(buf);
  }

  return slice;
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, 2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * Copyright (c) 2008 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <Python.h>

#include "sim/init.hh"

#include <marshal.h>
#include <zlib.h>

#include <iostream>
#include <list>
#include <string>
#include <vector>

#include "base/compiler.hh"
#include "base/cprintf.hh"
#include "base/logging.hh"
#include "base/types.hh"
#include "config/have_protobuf.hh"
#include "python/pybind11/pybind.hh"
#include "sim/async.hh"

#if HAVE_PROTOBUF
#include <google/protobuf/stubs/common.h>

#endif

namespace py = pybind11;

namespace gem5
{

// The python library is totally messed up with respect to constness,
// so make a simple macro to make life a little easier
#define PyCC(x) (const_cast<char *>(x))

EmbeddedPython::EmbeddedPython(const char *abspath, const char *modpath,
        const unsigned char *code, int zlen, int len)
    : abspath(abspath), modpath(modpath), code(code), zlen(zlen), len(len)
{
    getList().push_back(this);
}

std::list<EmbeddedPython *> &
EmbeddedPython::getList()
{
    static std::list<EmbeddedPython *> the_list;
    return the_list;
}

/*
 * Uncompress and unmarshal the code object stored in the
 * EmbeddedPython
 */
PyObject *
EmbeddedPython::getCode() const
{
    Bytef marshalled[len];
    uLongf unzlen = len;
    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
    if (ret != Z_OK)
        panic("Could not uncompress code: %s\n", zError(ret));
    assert(unzlen == (uLongf)len);

    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
}

bool
EmbeddedPython::addModule() const
{
    auto code = py::reinterpret_borrow<py::object>(getCode());
    // Ensure that "code" is not garbage collected.
    code.inc_ref();
    auto importer = py::module_::import("importer");
    importer.attr("add_module")(abspath, modpath, code);
    return true;
}

/*
 * Load and initialize all of the python parts of M5.
 */
int
EmbeddedPython::initAll()
{
    // Load the embedded python files into the embedded python importer.
    for (auto *embedded: getList()) {
        if (!embedded->addModule())
            return 1;
    }
    return 0;
}

EmbeddedPyBind::EmbeddedPyBind(const char *_name,
                               void (*init_func)(py::module_ &),
                               const char *_base)
    : initFunc(init_func), registered(false), name(_name), base(_base)
{
    getMap()[_name] = this;
}

EmbeddedPyBind::EmbeddedPyBind(const char *_name,
                               void (*init_func)(py::module_ &))
    : initFunc(init_func), registered(false), name(_name), base("")
{
    getMap()[_name] = this;
}

void
EmbeddedPyBind::init(py::module_ &m)
{
    if (!registered) {
        initFunc(m);
        registered = true;
    } else {
        cprintf("Warning: %s already registered.\n", name);
    }
}

bool
EmbeddedPyBind::depsReady() const
{
    return base.empty() || getMap()[base]->registered;
}

std::map<std::string, EmbeddedPyBind *> &
EmbeddedPyBind::getMap()
{
    static std::map<std::string, EmbeddedPyBind *> objs;
    return objs;
}

PyObject *
EmbeddedPyBind::initAll()
{
    std::list<EmbeddedPyBind *> pending;

    // The PyModuleDef structure needs to live as long as the module it
    // defines, so we'll leak it here so it lives forever. This is what
    // pybind11 does internally in the module_ constructor we were using. We
    // could theoretically keep track of the lifetime of the _m5 module
    // somehow and clean this up when it goes away, but that doesn't seem
    // worth the effort. The docs recommend statically allocating it, but that
    // could be unsafe on the very slim chance this method is called more than
    // once.
    auto *py_mod_def = new py::module_::module_def;
    py::module_ m_m5 = py::module_::create_extension_module(
            "_m5", nullptr, py_mod_def);
    m_m5.attr("__package__") = py::cast("_m5");

    pybind_init_core(m_m5);
    pybind_init_debug(m_m5);

    pybind_init_event(m_m5);
    pybind_init_stats(m_m5);

    for (auto &kv : getMap()) {
        auto &obj = kv.second;
        if (obj->base.empty()) {
            obj->init(m_m5);
        } else {
            pending.push_back(obj);
        }
    }

    while (!pending.empty()) {
        for (auto it = pending.begin(); it != pending.end(); ) {
            EmbeddedPyBind &obj = **it;
            if (obj.depsReady()) {
                obj.init(m_m5);
                it = pending.erase(it);
            } else {
                ++it;
            }
        }
    }

    return m_m5.ptr();
}

void
registerNativeModules()
{
    auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll);
    if (result == -1)
        panic("Failed to add _m5 to Python's inittab\n");
}

/*
 * Make the commands array weak so that they can be overridden (used
 * by unit tests to specify a different python main function.
 */
GEM5_WEAK const char *m5MainCommands[] = {
    "import m5",
    "m5.main()",
    0 // sentinel is required
};

/*
 * Start up the M5 simulator.  This mostly vectors into the python
 * main function.
 */
int
m5Main(int argc, char **_argv)
{
#if HAVE_PROTOBUF
    // Verify that the version of the protobuf library that we linked
    // against is compatible with the version of the headers we
    // compiled against.
    GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif

    typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
    std::vector<WArgUPtr> v_argv;
    std::vector<wchar_t *> vp_argv;
    v_argv.reserve(argc);
    vp_argv.reserve(argc);
    for (int i = 0; i < argc; i++) {
        v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
        vp_argv.emplace_back(v_argv.back().get());
    }

    wchar_t **argv = vp_argv.data();

    PySys_SetArgv(argc, argv);

    // We have to set things up in the special __main__ module
    PyObject *module = PyImport_AddModule(PyCC("__main__"));
    if (module == NULL)
        panic("Could not import __main__");
    PyObject *dict = PyModule_GetDict(module);

    // import the main m5 module
    PyObject *result;
    const char **command = m5MainCommands;

    // evaluate each command in the m5MainCommands array (basically a
    // bunch of python statements.
    while (*command) {
        result = PyRun_String(*command, Py_file_input, dict, dict);
        if (!result) {
            PyErr_Print();
            return 1;
        }
        Py_DECREF(result);

        command++;
    }

#if HAVE_PROTOBUF
    google::protobuf::ShutdownProtobufLibrary();
#endif

    return 0;
}

} // namespace gem5
<commit_msg>sim: Eliminate m5MainCommands and simplify calling m5.main.<commit_after>/*
 * Copyright (c) 2012, 2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * Copyright (c) 2008 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <Python.h>

#include "sim/init.hh"

#include <marshal.h>
#include <zlib.h>

#include <iostream>
#include <list>
#include <string>
#include <vector>

#include "base/compiler.hh"
#include "base/cprintf.hh"
#include "base/logging.hh"
#include "base/types.hh"
#include "config/have_protobuf.hh"
#include "python/pybind11/pybind.hh"
#include "sim/async.hh"

#if HAVE_PROTOBUF
#include <google/protobuf/stubs/common.h>

#endif

namespace py = pybind11;

namespace gem5
{

// The python library is totally messed up with respect to constness,
// so make a simple macro to make life a little easier
#define PyCC(x) (const_cast<char *>(x))

EmbeddedPython::EmbeddedPython(const char *abspath, const char *modpath,
        const unsigned char *code, int zlen, int len)
    : abspath(abspath), modpath(modpath), code(code), zlen(zlen), len(len)
{
    getList().push_back(this);
}

std::list<EmbeddedPython *> &
EmbeddedPython::getList()
{
    static std::list<EmbeddedPython *> the_list;
    return the_list;
}

/*
 * Uncompress and unmarshal the code object stored in the
 * EmbeddedPython
 */
PyObject *
EmbeddedPython::getCode() const
{
    Bytef marshalled[len];
    uLongf unzlen = len;
    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
    if (ret != Z_OK)
        panic("Could not uncompress code: %s\n", zError(ret));
    assert(unzlen == (uLongf)len);

    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
}

bool
EmbeddedPython::addModule() const
{
    auto code = py::reinterpret_borrow<py::object>(getCode());
    // Ensure that "code" is not garbage collected.
    code.inc_ref();
    auto importer = py::module_::import("importer");
    importer.attr("add_module")(abspath, modpath, code);
    return true;
}

/*
 * Load and initialize all of the python parts of M5.
 */
int
EmbeddedPython::initAll()
{
    // Load the embedded python files into the embedded python importer.
    for (auto *embedded: getList()) {
        if (!embedded->addModule())
            return 1;
    }
    return 0;
}

EmbeddedPyBind::EmbeddedPyBind(const char *_name,
                               void (*init_func)(py::module_ &),
                               const char *_base)
    : initFunc(init_func), registered(false), name(_name), base(_base)
{
    getMap()[_name] = this;
}

EmbeddedPyBind::EmbeddedPyBind(const char *_name,
                               void (*init_func)(py::module_ &))
    : initFunc(init_func), registered(false), name(_name), base("")
{
    getMap()[_name] = this;
}

void
EmbeddedPyBind::init(py::module_ &m)
{
    if (!registered) {
        initFunc(m);
        registered = true;
    } else {
        cprintf("Warning: %s already registered.\n", name);
    }
}

bool
EmbeddedPyBind::depsReady() const
{
    return base.empty() || getMap()[base]->registered;
}

std::map<std::string, EmbeddedPyBind *> &
EmbeddedPyBind::getMap()
{
    static std::map<std::string, EmbeddedPyBind *> objs;
    return objs;
}

PyObject *
EmbeddedPyBind::initAll()
{
    std::list<EmbeddedPyBind *> pending;

    // The PyModuleDef structure needs to live as long as the module it
    // defines, so we'll leak it here so it lives forever. This is what
    // pybind11 does internally in the module_ constructor we were using. We
    // could theoretically keep track of the lifetime of the _m5 module
    // somehow and clean this up when it goes away, but that doesn't seem
    // worth the effort. The docs recommend statically allocating it, but that
    // could be unsafe on the very slim chance this method is called more than
    // once.
    auto *py_mod_def = new py::module_::module_def;
    py::module_ m_m5 = py::module_::create_extension_module(
            "_m5", nullptr, py_mod_def);
    m_m5.attr("__package__") = py::cast("_m5");

    pybind_init_core(m_m5);
    pybind_init_debug(m_m5);

    pybind_init_event(m_m5);
    pybind_init_stats(m_m5);

    for (auto &kv : getMap()) {
        auto &obj = kv.second;
        if (obj->base.empty()) {
            obj->init(m_m5);
        } else {
            pending.push_back(obj);
        }
    }

    while (!pending.empty()) {
        for (auto it = pending.begin(); it != pending.end(); ) {
            EmbeddedPyBind &obj = **it;
            if (obj.depsReady()) {
                obj.init(m_m5);
                it = pending.erase(it);
            } else {
                ++it;
            }
        }
    }

    return m_m5.ptr();
}

void
registerNativeModules()
{
    auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll);
    if (result == -1)
        panic("Failed to add _m5 to Python's inittab\n");
}

/*
 * Start up the M5 simulator.  This mostly vectors into the python
 * main function.
 */
int
m5Main(int argc, char **_argv)
{
#if HAVE_PROTOBUF
    // Verify that the version of the protobuf library that we linked
    // against is compatible with the version of the headers we
    // compiled against.
    GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif

    typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
    std::vector<WArgUPtr> v_argv;
    std::vector<wchar_t *> vp_argv;
    v_argv.reserve(argc);
    vp_argv.reserve(argc);
    for (int i = 0; i < argc; i++) {
        v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
        vp_argv.emplace_back(v_argv.back().get());
    }

    wchar_t **argv = vp_argv.data();

    PySys_SetArgv(argc, argv);

    try {
        py::module_::import("m5").attr("main")();
    } catch (py::error_already_set &e) {
        if (e.matches(PyExc_SystemExit))
            return e.value().attr("code").cast<int>();

        std::cerr << e.what();
        return 1;
    }

#if HAVE_PROTOBUF
    google::protobuf::ShutdownProtobufLibrary();
#endif

    return 0;
}

} // namespace gem5
<|endoftext|>


<commit_before>#pragma once

#include <cstring>

#include "Core/Pair.hpp"
#include "Core/Hash.hpp"
#include "Math/Math.hpp"
#include "Memory/Allocator.hpp"

// Based on https://github.com/preshing/CompareIntegerMaps
// TODO: Make sure iterator will also go through zero pair

template <typename KeyType, typename ValueType>
class HashMap
{
public:
	using KeyValuePair = Pair<KeyType, ValueType>;

	class Iterator
	{
	private:
		KeyValuePair* current;
		KeyValuePair* end; // We need end to know when to stop in operator++()

		friend class HashMap;

	public:
		KeyValuePair& operator*() { return *current; }
		KeyValuePair* operator->() { return current; }

		bool operator==(Iterator other) const { return this->current == other.current; }
		bool operator!=(Iterator other) const { return operator==(other) == false; }

		Iterator& operator++()
		{
			if (current == end)
				return *this;

			while (true)
			{
				++current;

				if (current == end || current->first)
				{
					break;
				}
			}

			return *this;
		}

		Iterator operator++(int)
		{
			Iterator itr = *this;
			operator++();
			return itr;
		}
	};

private:
	Allocator* allocator;
	KeyValuePair* data;
	unsigned int population;
	unsigned int allocated;

	bool zeroUsed;
	KeyValuePair zeroPair;

	unsigned int GetIndex(unsigned int hash) const { return hash & (allocated - 1); }
	unsigned int GetOffset(KeyValuePair* a, KeyValuePair* b) const
	{
		return b >= a ? b - a : allocated + b - a;
	}

	void ReserveInternal(unsigned int desiredCount)
	{
		std::size_t newSize = desiredCount * sizeof(KeyValuePair);
		KeyValuePair* newData = static_cast<KeyValuePair*>(allocator->Allocate(newSize));
		std::memset(newData, 0, newSize);

		if (data != nullptr) // Old data exists
		{
			KeyValuePair* p = data;
			KeyValuePair* end = p + allocated;
			for (; p != end; ++p)
			{
				if (p->first) // Pair has value
				{
					for (unsigned int i = GetIndex(Hash::FNV1a_32(p->first));; i = GetIndex(i + 1))
					{
						if (!newData[i].first) // Insert here
						{
							newData[i] = *p;
							break;
						}
					}
				}
			}

			allocator->Deallocate(data);
		}

		data = newData;
		allocated = desiredCount;
	}

public:
	HashMap(Allocator* allocator) :
		allocator(allocator),
		data(nullptr),
		population(0),
		allocated(0),
		zeroUsed(false)
	{
		zeroPair = KeyValuePair{};
	}

	~HashMap()
	{
		if (data != nullptr)
		{
			KeyValuePair* itr = data;
			KeyValuePair* end = data + allocated;
			for (; itr != end; ++itr)
				if (itr->first)
					itr->second.~ValueType();

			allocator->Deallocate(data);
		}
	}

	Iterator Begin()
	{
		Iterator itr;
		itr.end = this->data + this->allocated;

		if (this->data != nullptr)
		{
			// Start at one before this->data
			itr.current = this->data - 1;

			// Find first valid item with the real increment operator
			++itr;
		}
		else
			itr.current = itr.end;

		return itr;
	}

	Iterator End()
	{
		Iterator itr;
		itr.end = this->data + this->allocated;
		itr.current = itr.end;
		return itr;
	}

	KeyValuePair* Lookup(KeyType key)
	{
		if (key)
		{
			if (data != nullptr)
			{
				for (unsigned int i = GetIndex(Hash::FNV1a_32(key));; i = GetIndex(i + 1))
				{
					KeyValuePair* pair = data + i;

					if (pair->first == key)
						return pair;

					if (!pair->first)
						return nullptr;
				}
			}
		}
		else if (zeroUsed)
			return &zeroPair;

		return nullptr;
	}

	KeyValuePair* Insert(KeyType key)
	{
		if (key)
		{
			if (data == nullptr)
				ReserveInternal(16);

			for (;;)
			for (unsigned int i = GetIndex(Hash::FNV1a_32(key));; i = GetIndex(i + 1))
			{
				KeyValuePair* pair = data + i;

				if (pair->first == key) // Found
					return pair;

				if (pair->first == 0) // Insert here
				{
					if ((population + 1) * 4 >= allocated * 3)
					{
						ReserveInternal(allocated * 2);
						break; // Back to outer loop, find first again
					}

					++population;
					pair->first = key;
					return pair;
				}
			}
		}
		else
		{
			if (zeroUsed == false)
			{
				zeroUsed = true;
				++population;

				// Even though we didn't use a regular slot, let's keep the sizing rules consistent
				if (population * 4 >= allocated * 3)
					ReserveInternal(allocated * 2);
			}

			return &zeroPair;
		}
	}

	void Remove(KeyValuePair* pair)
	{
		if (pair != &zeroPair)
		{
			if (data != nullptr &&
				pair >= data && pair < data + allocated &&
				pair->first)
			{
				// Remove this cell by shuffling neighboring cells
				// so there are no gaps in anyone's probe chain
				for (unsigned int i = GetIndex(pair - data + 1);; i = GetIndex(i + 1))
				{
					KeyValuePair* neighbor = data + i;

					if (!neighbor->first)
					{
						// There's nobody to swap with. Go ahead and clear this cell, then return
						pair->first = KeyType{};
						pair->second = ValueType{};
						population--;
						return;
					}

					KeyValuePair* ideal = data + GetIndex(Hash::FNV1a_32(neighbor->first));
					if (GetOffset(ideal, pair) < GetOffset(ideal, neighbor))
					{
						// Swap with neighbor, then make neighbor the new cell to remove.
						*pair = *neighbor;
						pair = neighbor;
					}
				}
			}
		}
		else if (zeroUsed) // Ignore if not in use
		{
			zeroUsed = false;
			pair->second = ValueType{};
			population--;
		}
	}

	void Reserve(unsigned int desiredPopulation)
	{
		if (desiredPopulation < population)
			return;

		unsigned int desiredSize = (desiredPopulation * 4 + 2) / 3;

		// Desired size is not a power-of-two
		if ((desiredSize & (desiredSize - 1)) != 0)
			desiredSize = Math::UpperPowerOfTwo(desiredSize);

		this->ReserveInternal(desiredSize);
	}
};
<commit_msg>Fix an issue in HashMap::ReserveInternal<commit_after>#pragma once

#include <cstring>

#include "Core/Pair.hpp"
#include "Core/Hash.hpp"
#include "Math/Math.hpp"
#include "Memory/Allocator.hpp"

// Based on https://github.com/preshing/CompareIntegerMaps
// TODO: Make sure iterator will also go through zero pair

template <typename KeyType, typename ValueType>
class HashMap
{
public:
	using KeyValuePair = Pair<KeyType, ValueType>;

	class Iterator
	{
	private:
		KeyValuePair* current;
		KeyValuePair* end; // We need end to know when to stop in operator++()

		friend class HashMap;

	public:
		KeyValuePair& operator*() { return *current; }
		KeyValuePair* operator->() { return current; }

		bool operator==(Iterator other) const { return this->current == other.current; }
		bool operator!=(Iterator other) const { return operator==(other) == false; }

		Iterator& operator++()
		{
			if (current == end)
				return *this;

			while (true)
			{
				++current;

				if (current == end || current->first)
				{
					break;
				}
			}

			return *this;
		}

		Iterator operator++(int)
		{
			Iterator itr = *this;
			operator++();
			return itr;
		}
	};

private:
	Allocator* allocator;
	KeyValuePair* data;
	unsigned int population;
	unsigned int allocated;

	bool zeroUsed;
	KeyValuePair zeroPair;

	unsigned int GetIndex(unsigned int hash) const { return hash & (allocated - 1); }
	unsigned int GetOffset(KeyValuePair* a, KeyValuePair* b) const
	{
		return b >= a ? b - a : allocated + b - a;
	}

	void ReserveInternal(unsigned int desiredCount)
	{
		std::size_t newSize = desiredCount * sizeof(KeyValuePair);
		KeyValuePair* newData = static_cast<KeyValuePair*>(allocator->Allocate(newSize));
		std::memset(newData, 0, newSize);

		if (data != nullptr) // Old data exists
		{
			KeyValuePair* p = data;
			KeyValuePair* end = p + allocated;

			// this->allocated needs to be set here because GetIndex() uses it
			allocated = desiredCount;

			for (; p != end; ++p)
			{
				if (p->first) // Pair has value
				{
					for (unsigned int i = GetIndex(Hash::FNV1a_32(p->first));; i = GetIndex(i + 1))
					{
						if (!newData[i].first) // Insert here
						{
							newData[i] = *p;
							break;
						}
					}
				}
			}

			allocator->Deallocate(data);
		}
		else
			allocated = desiredCount;

		data = newData;
	}

public:
	HashMap(Allocator* allocator) :
		allocator(allocator),
		data(nullptr),
		population(0),
		allocated(0),
		zeroUsed(false)
	{
		zeroPair = KeyValuePair{};
	}

	~HashMap()
	{
		if (data != nullptr)
		{
			KeyValuePair* itr = data;
			KeyValuePair* end = data + allocated;
			for (; itr != end; ++itr)
				if (itr->first)
					itr->second.~ValueType();

			allocator->Deallocate(data);
		}
	}

	Iterator Begin()
	{
		Iterator itr;
		itr.end = this->data + this->allocated;

		if (this->data != nullptr)
		{
			// Start at one before this->data
			itr.current = this->data - 1;

			// Find first valid item with the real increment operator
			++itr;
		}
		else
			itr.current = itr.end;

		return itr;
	}

	Iterator End()
	{
		Iterator itr;
		itr.end = this->data + this->allocated;
		itr.current = itr.end;
		return itr;
	}

	KeyValuePair* Lookup(KeyType key)
	{
		if (key)
		{
			if (data != nullptr)
			{
				for (unsigned int i = GetIndex(Hash::FNV1a_32(key));; i = GetIndex(i + 1))
				{
					KeyValuePair* pair = data + i;

					if (pair->first == key)
						return pair;

					if (!pair->first)
						return nullptr;
				}
			}
		}
		else if (zeroUsed)
			return &zeroPair;

		return nullptr;
	}

	KeyValuePair* Insert(KeyType key)
	{
		if (key)
		{
			if (data == nullptr)
				ReserveInternal(16);

			for (;;)
			for (unsigned int i = GetIndex(Hash::FNV1a_32(key));; i = GetIndex(i + 1))
			{
				KeyValuePair* pair = data + i;

				if (pair->first == key) // Found
					return pair;

				if (pair->first == 0) // Insert here
				{
					if ((population + 1) * 4 >= allocated * 3)
					{
						ReserveInternal(allocated * 2);
						break; // Back to outer loop, find first again
					}

					++population;
					pair->first = key;
					return pair;
				}
			}
		}
		else
		{
			if (zeroUsed == false)
			{
				zeroUsed = true;
				++population;

				// Even though we didn't use a regular slot, let's keep the sizing rules consistent
				if (population * 4 >= allocated * 3)
					ReserveInternal(allocated * 2);
			}

			return &zeroPair;
		}
	}

	void Remove(KeyValuePair* pair)
	{
		if (pair != &zeroPair)
		{
			if (data != nullptr &&
				pair >= data && pair < data + allocated &&
				pair->first)
			{
				// Remove this cell by shuffling neighboring cells
				// so there are no gaps in anyone's probe chain
				for (unsigned int i = GetIndex(pair - data + 1);; i = GetIndex(i + 1))
				{
					KeyValuePair* neighbor = data + i;

					if (!neighbor->first)
					{
						// There's nobody to swap with. Go ahead and clear this cell, then return
						pair->first = KeyType{};
						pair->second = ValueType{};
						population--;
						return;
					}

					KeyValuePair* ideal = data + GetIndex(Hash::FNV1a_32(neighbor->first));
					if (GetOffset(ideal, pair) < GetOffset(ideal, neighbor))
					{
						// Swap with neighbor, then make neighbor the new cell to remove.
						*pair = *neighbor;
						pair = neighbor;
					}
				}
			}
		}
		else if (zeroUsed) // Ignore if not in use
		{
			zeroUsed = false;
			pair->second = ValueType{};
			population--;
		}
	}

	void Reserve(unsigned int desiredPopulation)
	{
		if (desiredPopulation < population)
			return;

		unsigned int desiredSize = (desiredPopulation * 4 + 2) / 3;

		// Desired size is not a power-of-two
		if ((desiredSize & (desiredSize - 1)) != 0)
			desiredSize = Math::UpperPowerOfTwo(desiredSize);

		this->ReserveInternal(desiredSize);
	}
};
<|endoftext|>


<commit_before>#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cassert>

#include <algorithm>
#include <iostream>
#include <fstream>

using namespace std;

const int _fail = 1;
const int _fail_to_run = 2;
const int _fail_to_check = 3;

string itos(int a)
{
   string res = "";
   if (a == 0) return "0";
   while (a)
   {
      res += char(a % 10 + '0');
      a /= 10;
   }
   reverse(res.begin(), res.end());
   return res;
}

int compileCppCode(int id)
{
   if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/main.cpp").c_str()))
   {
      cerr << "Unable to copy file to sandbox" << endl;
      exit(_fail);
   }
   string cmd = "g++ ./sandbox/main.cpp -o ./sandbox/main "
            "-static -fno-optimize-sibling-calls -fno-strict-aliasing "
            "-DONLINE_JUDGE -lm -s -x c++ -O2 "
            "2>./submissions/" + itos(id) + ".compilationReport";
   int res = system(cmd.c_str());
   system("rm -f ./sandbox/main.cpp");
   return res;
}

int compilePascalCode(int id)
{
   if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/main.pas").c_str()))
   {
      cerr << "Unable to copy file to sandbox" << endl;
      exit(_fail);
   }
   string cmd = "fpc -dOLINE_JUDGE -So -XS -O2 ./sandbox/main.pas "
              "> ./submissions/" + itos(id) + ".compilationReport 2>&1 ";
   int res = system(cmd.c_str());
   system("rm -f ./sandbox/main.pas");
   return res;
}

int compileJavaCode(int id)
{
	if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/Main.java").c_str()))
	{
		cerr << "Unable to copy file to sandbox" << endl;
		exit(_fail);
	}
	system(("cp ./submissions/" + itos(id) + ".language ./sandbox/language").c_str());
	string cmd = "javac -cp \".;*\" ./sandbox/Main.java "
				 "> ./submissions/" + itos(id) + ".compilationReport 2>&1 ";
	int res = system(cmd.c_str());
	system("rm -f ./sandbox/Main.java");
	return res;
}

void updateStatus(int id, const string &status)
{
   ofstream st(("./submissions/" + itos(id) + ".status").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to update status of submission" << endl;
      exit(_fail);
   }
   st << status << endl;
   st.close();
}

string getSubmissionLanguage(int id)
{
   ifstream st(("./submissions/" + itos(id) + ".language").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to fetch language of submission" << endl;
      exit(_fail);
   }
   string lang;
   st >> lang;
   st.close();
   return lang;
}

string getSubmissionProblem(int id)
{
   ifstream st(("./submissions/" + itos(id) + ".problem").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to fetch submission's problem" << endl;
      exit(_fail);
   }
   string prob;
   st >> prob;
   st.close();
   return prob;
}

int getTesterExitCode()
{
   ifstream st("./sandbox/testerExitCode");
   if (!st.is_open())
   {
      cerr << "Unable to fetch submission's problem" << endl;
      exit(_fail);
   }
   int code;
   st >> code;
   st.close();
   return code;
}

int main(int argc, char** argv)
{
   assert(argc == 2);
   int id = atoi(argv[1]);
   cerr << "Testing started. SubmissionId = " << id << endl;
   system(("rm ./submissions/" + string(argv[1]) + ".score").c_str());
   updateStatus(id, "testing");

   string lang = getSubmissionLanguage(id);
   string problem = getSubmissionProblem(id);
   cerr << "Problem = " << problem << endl;
   cerr << "Language = " << lang << endl;

   int error = 0;
   if (lang == "pascal") error = compilePascalCode(id);
   else if (lang == "cpp") error = compileCppCode(id);
   else if (lang == "java") error = compileJavaCode(id);
   else
   {
      cerr << "Unknown language" << endl;
      return _fail;
   }

   if (!error)
   {
      system(("./tester tasks/" + problem + " >./sandbox/currentResult; echo $? >./sandbox/testerExitCode").c_str());
      int res = getTesterExitCode();
      if (res == _fail || res == _fail_to_run)
      {
         updateStatus(id, "FAIL");
         cerr << "Fatal error occured while running. Abort testing." << endl;
         return _fail;
      }
      if (res == _fail_to_check)
      {
         updateStatus(id, "FAIL");
         cerr << "Fatal error occured while checking. Abort testing." << endl;
         return _fail;
      }
      cerr << "Submission successfully tested" << endl;
      if (system(("tasks/" + problem + "/grade " + itos(id) + " tasks/" + problem + " <./sandbox/currentResult").c_str()))
      {
         updateStatus(id, "FAIL");
         cerr << "Cannot grade submission. Abort testing." << endl;
         return _fail;
      }
      cerr << "Submission successfully graded" << endl;
      cerr << "Testing completed" << endl;
      updateStatus(id, "tested");
      //system("rm -f ./sandbox/currentResult");
      system("rm ./sandbox/language");
   }
   else
   {
      updateStatus(id, "CE");
      cerr << "Compilation error" << endl;
      system(("echo 0 >./submissions/" + itos(id) + ".score").c_str());
   }
   return 0;
}
<commit_msg>Fix pascal compilation routine<commit_after>#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cassert>

#include <algorithm>
#include <iostream>
#include <fstream>

using namespace std;

const int _fail = 1;
const int _fail_to_run = 2;
const int _fail_to_check = 3;

string itos(int a)
{
   string res = "";
   if (a == 0) return "0";
   while (a)
   {
      res += char(a % 10 + '0');
      a /= 10;
   }
   reverse(res.begin(), res.end());
   return res;
}

int compileCppCode(int id)
{
   if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/main.cpp").c_str()))
   {
      cerr << "Unable to copy file to sandbox" << endl;
      exit(_fail);
   }
   string cmd = "g++ ./sandbox/main.cpp -o ./sandbox/main "
            "-static -fno-optimize-sibling-calls -fno-strict-aliasing "
            "-DONLINE_JUDGE -lm -s -x c++ -O2 "
            "2>./submissions/" + itos(id) + ".compilationReport";
   int res = system(cmd.c_str());
   system("rm -f ./sandbox/main.cpp");
   return res;
}

int compilePascalCode(int id)
{
   if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/main.pas").c_str()))
   {
      cerr << "Unable to copy file to sandbox" << endl;
      exit(_fail);
   }
   string cmd = "fpc -dONLINE_JUDGE -So -XS -O2 ./sandbox/main.pas "
              "> ./submissions/" + itos(id) + ".compilationReport 2>&1 ";
   int res = system(cmd.c_str());
   system("rm -f ./sandbox/main.pas");
   return res;
}

int compileJavaCode(int id)
{
	if (system(("cp ./submissions/" + itos(id) + ".code ./sandbox/Main.java").c_str()))
	{
		cerr << "Unable to copy file to sandbox" << endl;
		exit(_fail);
	}
	system(("cp ./submissions/" + itos(id) + ".language ./sandbox/language").c_str());
	string cmd = "javac -cp \".;*\" ./sandbox/Main.java "
				 "> ./submissions/" + itos(id) + ".compilationReport 2>&1 ";
	int res = system(cmd.c_str());
	system("rm -f ./sandbox/Main.java");
	return res;
}

void updateStatus(int id, const string &status)
{
   ofstream st(("./submissions/" + itos(id) + ".status").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to update status of submission" << endl;
      exit(_fail);
   }
   st << status << endl;
   st.close();
}

string getSubmissionLanguage(int id)
{
   ifstream st(("./submissions/" + itos(id) + ".language").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to fetch language of submission" << endl;
      exit(_fail);
   }
   string lang;
   st >> lang;
   st.close();
   return lang;
}

string getSubmissionProblem(int id)
{
   ifstream st(("./submissions/" + itos(id) + ".problem").c_str());
   if (!st.is_open())
   {
      cerr << "Unable to fetch submission's problem" << endl;
      exit(_fail);
   }
   string prob;
   st >> prob;
   st.close();
   return prob;
}

int getTesterExitCode()
{
   ifstream st("./sandbox/testerExitCode");
   if (!st.is_open())
   {
      cerr << "Unable to fetch submission's problem" << endl;
      exit(_fail);
   }
   int code;
   st >> code;
   st.close();
   return code;
}

int main(int argc, char** argv)
{
   assert(argc == 2);
   int id = atoi(argv[1]);
   cerr << "Testing started. SubmissionId = " << id << endl;
   system(("rm ./submissions/" + string(argv[1]) + ".score").c_str());
   updateStatus(id, "testing");

   string lang = getSubmissionLanguage(id);
   string problem = getSubmissionProblem(id);
   cerr << "Problem = " << problem << endl;
   cerr << "Language = " << lang << endl;

   int error = 0;
   if (lang == "pascal") error = compilePascalCode(id);
   else if (lang == "cpp") error = compileCppCode(id);
   else if (lang == "java") error = compileJavaCode(id);
   else
   {
      cerr << "Unknown language" << endl;
      return _fail;
   }

   if (!error)
   {
      system(("./tester tasks/" + problem + " >./sandbox/currentResult; echo $? >./sandbox/testerExitCode").c_str());
      int res = getTesterExitCode();
      if (res == _fail || res == _fail_to_run)
      {
         updateStatus(id, "FAIL");
         cerr << "Fatal error occured while running. Abort testing." << endl;
         return _fail;
      }
      if (res == _fail_to_check)
      {
         updateStatus(id, "FAIL");
         cerr << "Fatal error occured while checking. Abort testing." << endl;
         return _fail;
      }
      cerr << "Submission successfully tested" << endl;
      if (system(("tasks/" + problem + "/grade " + itos(id) + " tasks/" + problem + " <./sandbox/currentResult").c_str()))
      {
         updateStatus(id, "FAIL");
         cerr << "Cannot grade submission. Abort testing." << endl;
         return _fail;
      }
      cerr << "Submission successfully graded" << endl;
      cerr << "Testing completed" << endl;
      updateStatus(id, "tested");
      //system("rm -f ./sandbox/currentResult");
      system("rm ./sandbox/language");
   }
   else
   {
      updateStatus(id, "CE");
      cerr << "Compilation error" << endl;
      system(("echo 0 >./submissions/" + itos(id) + ".score").c_str());
   }
   return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
 *
 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
 *
 * Other contributors:
 *   Robert O'Callahan <roc+@cs.cmu.edu>
 *   David Baron <dbaron@fas.harvard.edu>
 *   Christian Biesinger <cbiesinger@web.de>
 *   Randall Jesup <rjesup@wgate.com>
 *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
 *   Josh Soref <timeless@mac.com>
 *   Boris Zbarsky <bzbarsky@mit.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Alternatively, the contents of this file may be used under the terms
 * of either the Mozilla Public License Version 1.1, found at
 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
 * (the "GPL"), in which case the provisions of the MPL or the GPL are
 * applicable instead of those above.  If you wish to allow use of your
 * version of this file only under the terms of one of those two
 * licenses (the MPL or the GPL) and not to allow others to use your
 * version of this file under the LGPL, indicate your decision by
 * deletingthe provisions above and replace them with the notice and
 * other provisions required by the MPL or the GPL, as the case may be.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under any of the LGPL, the MPL or the GPL.
 */

#include "config.h"
#include "core/rendering/RenderLayerRepainter.h"

#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderLayerBacking.h"
#include "core/rendering/RenderView.h"

namespace WebCore {

RenderLayerRepainter::RenderLayerRepainter(RenderLayerModelObject* renderer)
    : m_renderer(renderer)
    , m_repaintStatus(NeedsNormalRepaint)
{
}

void RenderLayerRepainter::repaintAfterLayout(RenderGeometryMap* geometryMap, bool shouldCheckForRepaint)
{
    if (m_renderer->layer()->hasVisibleContent()) {
        RenderView* view = m_renderer->view();
        ASSERT(view);
        // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
        // mapping between them and the RenderObjects. It would be neat to enable
        // LayoutState outside the layout() phase and use it here.
        ASSERT(!view->layoutStateEnabled());

        RenderLayerModelObject* repaintContainer = m_renderer->containerForRepaint();
        LayoutRect oldRepaintRect = m_repaintRect;
        LayoutRect oldOutlineBox = m_outlineBox;
        computeRepaintRects(repaintContainer, geometryMap);

        // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
        // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
        if (shouldCheckForRepaint) {
            if (view && !view->document().printing()) {
                if (m_repaintStatus & NeedsFullRepaint) {
                    m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect));
                    if (m_repaintRect != oldRepaintRect)
                        m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
                } else if (shouldRepaintAfterLayout()) {
                    m_renderer->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
                }
            }
        }
    } else {
        clearRepaintRects();
    }

    m_repaintStatus = NeedsNormalRepaint;

}

void RenderLayerRepainter::clearRepaintRects()
{
    ASSERT(!m_renderer->layer()->hasVisibleContent());

    m_repaintRect = IntRect();
    m_outlineBox = IntRect();
}

void RenderLayerRepainter::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
{
    ASSERT(m_renderer->layer()->hasVisibleContent());

    m_repaintRect = m_renderer->clippedOverflowRectForRepaint(repaintContainer);
    m_outlineBox = m_renderer->outlineBoundsForRepaint(repaintContainer, geometryMap);
}

void RenderLayerRepainter::computeRepaintRectsIncludingDescendants()
{
    // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
    // We should make this more efficient.
    // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
    computeRepaintRects(m_renderer->containerForRepaint());

    for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling())
        layer->repainter().computeRepaintRectsIncludingDescendants();
}

inline bool RenderLayerRepainter::shouldRepaintAfterLayout() const
{
    if (m_repaintStatus == NeedsNormalRepaint)
        return true;

    // Composited layers that were moved during a positioned movement only
    // layout, don't need to be repainted. They just need to be recomposited.
    ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
    return !m_renderer->isComposited() || (m_renderer->isComposited() && m_renderer->layer()->backing()->paintsIntoCompositedAncestor());
}

// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
void RenderLayerRepainter::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer)
{
    m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_renderer->clippedOverflowRectForRepaint(repaintContainer)));

    for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) {
        if (!curr->isComposited())
            curr->repainter().repaintIncludingNonCompositingDescendants(repaintContainer);
    }
}

LayoutRect RenderLayerRepainter::repaintRectIncludingNonCompositingDescendants() const
{
    LayoutRect repaintRect = m_repaintRect;
    for (RenderLayer* child = m_renderer->layer()->firstChild(); child; child = child->nextSibling()) {
        // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
        if (child->isComposited())
            continue;

        repaintRect.unite(child->repainter().repaintRectIncludingNonCompositingDescendants());
    }
    return repaintRect;
}

} // Namespace WebCore
<commit_msg>Remove a triggering ASSERT<commit_after>/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
 *
 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
 *
 * Other contributors:
 *   Robert O'Callahan <roc+@cs.cmu.edu>
 *   David Baron <dbaron@fas.harvard.edu>
 *   Christian Biesinger <cbiesinger@web.de>
 *   Randall Jesup <rjesup@wgate.com>
 *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
 *   Josh Soref <timeless@mac.com>
 *   Boris Zbarsky <bzbarsky@mit.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Alternatively, the contents of this file may be used under the terms
 * of either the Mozilla Public License Version 1.1, found at
 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
 * (the "GPL"), in which case the provisions of the MPL or the GPL are
 * applicable instead of those above.  If you wish to allow use of your
 * version of this file only under the terms of one of those two
 * licenses (the MPL or the GPL) and not to allow others to use your
 * version of this file under the LGPL, indicate your decision by
 * deletingthe provisions above and replace them with the notice and
 * other provisions required by the MPL or the GPL, as the case may be.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under any of the LGPL, the MPL or the GPL.
 */

#include "config.h"
#include "core/rendering/RenderLayerRepainter.h"

#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderLayerBacking.h"
#include "core/rendering/RenderView.h"

namespace WebCore {

RenderLayerRepainter::RenderLayerRepainter(RenderLayerModelObject* renderer)
    : m_renderer(renderer)
    , m_repaintStatus(NeedsNormalRepaint)
{
}

void RenderLayerRepainter::repaintAfterLayout(RenderGeometryMap* geometryMap, bool shouldCheckForRepaint)
{
    if (m_renderer->layer()->hasVisibleContent()) {
        RenderView* view = m_renderer->view();
        ASSERT(view);
        // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
        // mapping between them and the RenderObjects. It would be neat to enable
        // LayoutState outside the layout() phase and use it here.
        ASSERT(!view->layoutStateEnabled());

        RenderLayerModelObject* repaintContainer = m_renderer->containerForRepaint();
        LayoutRect oldRepaintRect = m_repaintRect;
        LayoutRect oldOutlineBox = m_outlineBox;
        computeRepaintRects(repaintContainer, geometryMap);

        // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
        // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
        if (shouldCheckForRepaint) {
            if (view && !view->document().printing()) {
                if (m_repaintStatus & NeedsFullRepaint) {
                    m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect));
                    if (m_repaintRect != oldRepaintRect)
                        m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
                } else if (shouldRepaintAfterLayout()) {
                    m_renderer->repaintAfterLayoutIfNeeded(repaintContainer, oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox);
                }
            }
        }
    } else {
        clearRepaintRects();
    }

    m_repaintStatus = NeedsNormalRepaint;

}

void RenderLayerRepainter::clearRepaintRects()
{
    ASSERT(!m_renderer->layer()->hasVisibleContent());

    m_repaintRect = IntRect();
    m_outlineBox = IntRect();
}

void RenderLayerRepainter::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap)
{
    m_repaintRect = m_renderer->clippedOverflowRectForRepaint(repaintContainer);
    m_outlineBox = m_renderer->outlineBoundsForRepaint(repaintContainer, geometryMap);
}

void RenderLayerRepainter::computeRepaintRectsIncludingDescendants()
{
    // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects.
    // We should make this more efficient.
    // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
    computeRepaintRects(m_renderer->containerForRepaint());

    for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling())
        layer->repainter().computeRepaintRectsIncludingDescendants();
}

inline bool RenderLayerRepainter::shouldRepaintAfterLayout() const
{
    if (m_repaintStatus == NeedsNormalRepaint)
        return true;

    // Composited layers that were moved during a positioned movement only
    // layout, don't need to be repainted. They just need to be recomposited.
    ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
    return !m_renderer->isComposited() || (m_renderer->isComposited() && m_renderer->layer()->backing()->paintsIntoCompositedAncestor());
}

// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
void RenderLayerRepainter::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer)
{
    m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_renderer->clippedOverflowRectForRepaint(repaintContainer)));

    for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) {
        if (!curr->isComposited())
            curr->repainter().repaintIncludingNonCompositingDescendants(repaintContainer);
    }
}

LayoutRect RenderLayerRepainter::repaintRectIncludingNonCompositingDescendants() const
{
    LayoutRect repaintRect = m_repaintRect;
    for (RenderLayer* child = m_renderer->layer()->firstChild(); child; child = child->nextSibling()) {
        // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin.
        if (child->isComposited())
            continue;

        repaintRect.unite(child->repainter().repaintRectIncludingNonCompositingDescendants());
    }
    return repaintRect;
}

} // Namespace WebCore
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 "google/cloud/storage/internal/object_read_streambuf.h"
#include "google/cloud/storage/hash_mismatch_error.h"
#include "absl/memory/memory.h"
#include <cstring>

namespace google {
namespace cloud {
namespace storage {
inline namespace STORAGE_CLIENT_NS {
namespace internal {

ObjectReadStreambuf::ObjectReadStreambuf(
    ReadObjectRangeRequest const& request,
    std::unique_ptr<ObjectReadSource> source, std::streamoff pos_in_stream)
    : source_(std::move(source)),
      source_pos_(pos_in_stream),
      hash_validator_(CreateHashValidator(request)) {}

ObjectReadStreambuf::ObjectReadStreambuf(ReadObjectRangeRequest const&,
                                         Status status)
    : source_(new ObjectReadErrorSource(status)),
      source_pos_(-1),
      hash_validator_(absl::make_unique<NullHashValidator>()),
      status_(std::move(status)) {}

ObjectReadStreambuf::pos_type ObjectReadStreambuf::seekpos(
    pos_type /*pos*/, std::ios_base::openmode /*which*/) {
  // TODO(#4013): Implement proper seeking.
  return -1;
}

ObjectReadStreambuf::pos_type ObjectReadStreambuf::seekoff(
    off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) {
  // TODO(#4013): Implement proper seeking.
  // Seeking is non-trivial because the hash validator and `source_` have to be
  // recreated in the general case, which doesn't fit the current code
  // organization.  We can, however, at least implement the bare minimum of this
  // function allowing `tellg()` to work.
  if (which == std::ios_base::in && dir == std::ios_base::cur && off == 0) {
    return source_pos_ - in_avail();
  }
  return -1;
}

bool ObjectReadStreambuf::IsOpen() const { return source_->IsOpen(); }

void ObjectReadStreambuf::Close() {
  auto response = source_->Close();
  if (!response.ok()) {
    ReportError(std::move(response).status());
  }
}

ObjectReadStreambuf::int_type ObjectReadStreambuf::ReportError(Status status) {
  // The only way to report errors from a std::basic_streambuf<> (which this
  // class derives from) is to throw exceptions:
  //   https://stackoverflow.com/questions/50716688/how-to-set-the-badbit-of-a-stream-by-a-customized-streambuf
  // but we need to be able to report errors when the application has disabled
  // exceptions via `-fno-exceptions` or a similar option. In that case we set
  // `status_`, and report the error as an EOF. This is obviously not ideal,
  // but it is the best we can do when the application disables the standard
  // mechanism to signal errors.
  if (status.ok()) {
    return traits_type::eof();
  }
  status_ = std::move(status);
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
  google::cloud::internal::ThrowStatus(status_);
#else
  return traits_type::eof();
#endif  // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
}

void ObjectReadStreambuf::ThrowHashMismatchDelegate(const char* function_name) {
  std::string msg;
  msg += function_name;
  msg += "(): mismatched hashes in download";
  msg += ", computed=";
  msg += computed_hash();
  msg += ", received=";
  msg += received_hash();
  if (status_.ok()) {
    // If there is an existing error, we should report that instead because
    // it is more specific, for example, every permanent network error will
    // produce invalid checksums, but that is not the interesting information.
    status_ = Status(StatusCode::kDataLoss, msg);
  }
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
  // The only way to report errors from a std::basic_streambuf<> (which this
  // class derives from) is to throw exceptions:
  //   https://stackoverflow.com/questions/50716688/how-to-set-the-badbit-of-a-stream-by-a-customized-streambuf
  // but we need to be able to report errors when the application has
  // disabled exceptions via `-fno-exceptions` or a similar option. In that
  // case we set `status_`, and report the error as an 0-byte read. This is
  // obviously not ideal, but it is the best we can do when the application
  // disables the standard mechanism to signal errors.
  throw HashMismatchError(msg, received_hash(), computed_hash());
#endif  // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
}

bool ObjectReadStreambuf::ValidateHashes(char const* function_name) {
  // This function is called once the stream is "closed" (either an explicit
  // `Close()` call or a permanent error). After this point the validator is
  // not usable.
  auto validator = std::move(hash_validator_);
  hash_validator_result_ = std::move(*validator).Finish();
  if (!hash_validator_result_.is_mismatch) return true;
  ThrowHashMismatchDelegate(function_name);
  return false;
}

bool ObjectReadStreambuf::CheckPreconditions(char const* function_name) {
  if (hash_validator_result_.is_mismatch) {
    ThrowHashMismatchDelegate(function_name);
  }
  if (in_avail() != 0) return true;
  return status_.ok() && IsOpen();
}

ObjectReadStreambuf::int_type ObjectReadStreambuf::underflow() {
  if (!CheckPreconditions(__func__)) return traits_type::eof();

  // If this function is called, then the internal buffer must be empty. We will
  // perform a read into a new buffer and reset the input area to use this
  // buffer.
  auto constexpr kInitialPeekRead = 128 * 1024;
  std::vector<char> buffer(kInitialPeekRead);
  auto const offset = xsgetn(buffer.data(), kInitialPeekRead);
  if (offset == 0) return traits_type::eof();

  buffer.resize(offset);
  buffer.swap(current_ios_buffer_);
  char* data = current_ios_buffer_.data();
  setg(data, data, data + current_ios_buffer_.size());
  return traits_type::to_int_type(*data);
}

std::streamsize ObjectReadStreambuf::xsgetn(char* s, std::streamsize count) {
  if (!CheckPreconditions(__func__)) return 0;

  // This function optimizes stream.read(), the data is copied directly from the
  // data source (typically libcurl) into a buffer provided by the application.
  std::streamsize offset = 0;

  // Maybe the internal get area is enough to satisfy this request, no need to
  // read more in that case:
  auto from_internal = (std::min)(count, in_avail());
  if (from_internal > 0) {
    std::memcpy(s, gptr(), static_cast<std::size_t>(from_internal));
  }
  gbump(static_cast<int>(from_internal));
  offset += from_internal;
  // If we got all the data requested, there is no need for additional reads.
  // Likewise, if the underlying transport is closed, whatever we got is all the
  // data available.
  if (offset >= count || !IsOpen()) return offset;

  auto const* function_name = __func__;
  auto run_validator_if_closed = [this, function_name, &offset](Status s) {
    ReportError(std::move(s));
    // Only validate the checksums once the stream is closed.
    if (IsOpen()) return offset;
    return ValidateHashes(function_name) ? offset : 0;
  };

  StatusOr<ReadSourceResult> read =
      source_->Read(s + offset, static_cast<std::size_t>(count - offset));
  // If there was an error set the internal state, but we still return the
  // number of bytes.
  if (!read) return run_validator_if_closed(std::move(read).status());

  hash_validator_->Update(s + offset, read->bytes_received);
  offset += static_cast<std::streamsize>(read->bytes_received);
  source_pos_ += static_cast<std::streamoff>(read->bytes_received);

  for (auto const& kv : read->response.headers) {
    hash_validator_->ProcessHeader(kv.first, kv.second);
    headers_.emplace(kv.first, kv.second);
  }
  return run_validator_if_closed(Status());
}

}  // namespace internal
}  // namespace STORAGE_CLIENT_NS
}  // namespace storage
}  // namespace cloud
}  // namespace google
<commit_msg>fix(storage): build with MSVC+x86 (#6986)<commit_after>// Copyright 2021 Google LLC
//
// 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 "google/cloud/storage/internal/object_read_streambuf.h"
#include "google/cloud/storage/hash_mismatch_error.h"
#include "absl/memory/memory.h"
#include <cstring>

namespace google {
namespace cloud {
namespace storage {
inline namespace STORAGE_CLIENT_NS {
namespace internal {

ObjectReadStreambuf::ObjectReadStreambuf(
    ReadObjectRangeRequest const& request,
    std::unique_ptr<ObjectReadSource> source, std::streamoff pos_in_stream)
    : source_(std::move(source)),
      source_pos_(pos_in_stream),
      hash_validator_(CreateHashValidator(request)) {}

ObjectReadStreambuf::ObjectReadStreambuf(ReadObjectRangeRequest const&,
                                         Status status)
    : source_(new ObjectReadErrorSource(status)),
      source_pos_(-1),
      hash_validator_(absl::make_unique<NullHashValidator>()),
      status_(std::move(status)) {}

ObjectReadStreambuf::pos_type ObjectReadStreambuf::seekpos(
    pos_type /*pos*/, std::ios_base::openmode /*which*/) {
  // TODO(#4013): Implement proper seeking.
  return -1;
}

ObjectReadStreambuf::pos_type ObjectReadStreambuf::seekoff(
    off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) {
  // TODO(#4013): Implement proper seeking.
  // Seeking is non-trivial because the hash validator and `source_` have to be
  // recreated in the general case, which doesn't fit the current code
  // organization.  We can, however, at least implement the bare minimum of this
  // function allowing `tellg()` to work.
  if (which == std::ios_base::in && dir == std::ios_base::cur && off == 0) {
    return source_pos_ - in_avail();
  }
  return -1;
}

bool ObjectReadStreambuf::IsOpen() const { return source_->IsOpen(); }

void ObjectReadStreambuf::Close() {
  auto response = source_->Close();
  if (!response.ok()) {
    ReportError(std::move(response).status());
  }
}

ObjectReadStreambuf::int_type ObjectReadStreambuf::ReportError(Status status) {
  // The only way to report errors from a std::basic_streambuf<> (which this
  // class derives from) is to throw exceptions:
  //   https://stackoverflow.com/questions/50716688/how-to-set-the-badbit-of-a-stream-by-a-customized-streambuf
  // but we need to be able to report errors when the application has disabled
  // exceptions via `-fno-exceptions` or a similar option. In that case we set
  // `status_`, and report the error as an EOF. This is obviously not ideal,
  // but it is the best we can do when the application disables the standard
  // mechanism to signal errors.
  if (status.ok()) {
    return traits_type::eof();
  }
  status_ = std::move(status);
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
  google::cloud::internal::ThrowStatus(status_);
#else
  return traits_type::eof();
#endif  // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
}

void ObjectReadStreambuf::ThrowHashMismatchDelegate(const char* function_name) {
  std::string msg;
  msg += function_name;
  msg += "(): mismatched hashes in download";
  msg += ", computed=";
  msg += computed_hash();
  msg += ", received=";
  msg += received_hash();
  if (status_.ok()) {
    // If there is an existing error, we should report that instead because
    // it is more specific, for example, every permanent network error will
    // produce invalid checksums, but that is not the interesting information.
    status_ = Status(StatusCode::kDataLoss, msg);
  }
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
  // The only way to report errors from a std::basic_streambuf<> (which this
  // class derives from) is to throw exceptions:
  //   https://stackoverflow.com/questions/50716688/how-to-set-the-badbit-of-a-stream-by-a-customized-streambuf
  // but we need to be able to report errors when the application has
  // disabled exceptions via `-fno-exceptions` or a similar option. In that
  // case we set `status_`, and report the error as an 0-byte read. This is
  // obviously not ideal, but it is the best we can do when the application
  // disables the standard mechanism to signal errors.
  throw HashMismatchError(msg, received_hash(), computed_hash());
#endif  // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
}

bool ObjectReadStreambuf::ValidateHashes(char const* function_name) {
  // This function is called once the stream is "closed" (either an explicit
  // `Close()` call or a permanent error). After this point the validator is
  // not usable.
  auto validator = std::move(hash_validator_);
  hash_validator_result_ = std::move(*validator).Finish();
  if (!hash_validator_result_.is_mismatch) return true;
  ThrowHashMismatchDelegate(function_name);
  return false;
}

bool ObjectReadStreambuf::CheckPreconditions(char const* function_name) {
  if (hash_validator_result_.is_mismatch) {
    ThrowHashMismatchDelegate(function_name);
  }
  if (in_avail() != 0) return true;
  return status_.ok() && IsOpen();
}

ObjectReadStreambuf::int_type ObjectReadStreambuf::underflow() {
  if (!CheckPreconditions(__func__)) return traits_type::eof();

  // If this function is called, then the internal buffer must be empty. We will
  // perform a read into a new buffer and reset the input area to use this
  // buffer.
  auto constexpr kInitialPeekRead = 128 * 1024;
  std::vector<char> buffer(kInitialPeekRead);
  auto const offset = xsgetn(buffer.data(), kInitialPeekRead);
  if (offset == 0) return traits_type::eof();

  buffer.resize(static_cast<std::size_t>(offset));
  buffer.swap(current_ios_buffer_);
  char* data = current_ios_buffer_.data();
  setg(data, data, data + current_ios_buffer_.size());
  return traits_type::to_int_type(*data);
}

std::streamsize ObjectReadStreambuf::xsgetn(char* s, std::streamsize count) {
  if (!CheckPreconditions(__func__)) return 0;

  // This function optimizes stream.read(), the data is copied directly from the
  // data source (typically libcurl) into a buffer provided by the application.
  std::streamsize offset = 0;

  // Maybe the internal get area is enough to satisfy this request, no need to
  // read more in that case:
  auto from_internal = (std::min)(count, in_avail());
  if (from_internal > 0) {
    std::memcpy(s, gptr(), static_cast<std::size_t>(from_internal));
  }
  gbump(static_cast<int>(from_internal));
  offset += from_internal;
  // If we got all the data requested, there is no need for additional reads.
  // Likewise, if the underlying transport is closed, whatever we got is all the
  // data available.
  if (offset >= count || !IsOpen()) return offset;

  auto const* function_name = __func__;
  auto run_validator_if_closed = [this, function_name, &offset](Status s) {
    ReportError(std::move(s));
    // Only validate the checksums once the stream is closed.
    if (IsOpen()) return offset;
    return ValidateHashes(function_name) ? offset : 0;
  };

  StatusOr<ReadSourceResult> read =
      source_->Read(s + offset, static_cast<std::size_t>(count - offset));
  // If there was an error set the internal state, but we still return the
  // number of bytes.
  if (!read) return run_validator_if_closed(std::move(read).status());

  hash_validator_->Update(s + offset, read->bytes_received);
  offset += static_cast<std::streamsize>(read->bytes_received);
  source_pos_ += static_cast<std::streamoff>(read->bytes_received);

  for (auto const& kv : read->response.headers) {
    hash_validator_->ProcessHeader(kv.first, kv.second);
    headers_.emplace(kv.first, kv.second);
  }
  return run_validator_if_closed(Status());
}

}  // namespace internal
}  // namespace STORAGE_CLIENT_NS
}  // namespace storage
}  // namespace cloud
}  // namespace google
<|endoftext|>