<commit_before>/*******************************************************
 * Copyright (c) 2015-2019, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once

#include <fg/defines.h>
#include <fg/exception.h>
#include <err_common.hpp>

#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>

#include <vector>
#include <iterator>

static const float BLACK[]   = {0.0f    , 0.0f    , 0.0f    , 1.0f};
static const float GRAY[]    = {0.85f   , 0.85f   , 0.85f   , 1.0f};
static const float WHITE[]   = {1.0f    , 1.0f    , 1.0f    , 1.0f};
static const float AF_BLUE[] = {0.0588f , 0.1137f , 0.2745f , 1.0f};
static const glm::mat4 IDENTITY(1.0f);

/* clamp the float to [0-1] range
 *
 * @pValue is the value to be clamped
 */
float clampTo01(const float pValue);

/* Convert forge type enum to OpenGL enum for GL_* type
 *
 * @pValue is the forge type enum
 *
 * @return GL_* typedef for data type
 */
gl::GLenum dtype2gl(const forge::dtype pValue);

/* Convert forge channel format enum to OpenGL enum to indicate color component layout
 *
 * @pValue is the forge type enum
 *
 * @return OpenGL enum indicating color component layout
 */
gl::GLenum ctype2gl(const forge::ChannelFormat pMode);

/* Convert forge channel format enum to OpenGL enum to indicate color component layout
 *
 * This function is used to group color component layout formats based
 * on number of components.
 *
 * @pValue is the forge type enum
 *
 * @return OpenGL enum indicating color component layout
 */
gl::GLenum ictype2gl(const forge::ChannelFormat pMode);

/* Create OpenGL buffer object
 *
 * @pTarget should be either GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER
 * @pSize is the size of the data in bytes
 * @pPtr is the pointer to host data. This can be NULL
 * @pUsage should be either GL_STATIC_DRAW or GL_DYNAMIC_DRAW
 *
 * @return OpenGL buffer object identifier
 */
template<typename T>
gl::GLuint createBuffer(gl::GLenum pTarget, size_t pSize, const T* pPtr, gl::GLenum pUsage)
{
    gl::GLuint retVal = 0;
    gl::glGenBuffers(1, &retVal);
    gl::glBindBuffer(pTarget, retVal);
    gl::glBufferData(pTarget, pSize*sizeof(T), pPtr, pUsage);
    gl::glBindBuffer(pTarget, 0);
    return retVal;
}

#ifdef OS_WIN
/* Get the paths to font files in Windows system directory
 *
 * @pFiles is the output vector to which font file paths are appended to.
 * @pDir is the directory from which font files are looked up
 * @pExt is the target font file extension we are looking for.
 */
void getFontFilePaths(std::vector<std::string>& pFiles,
                      const std::string& pDir,
                      const std::string& pExt);
#endif

/* Convert float value to string with given precision
 *
 * @pVal is the float value whose string representation is requested.
 * @pPrecision is the precision of the float used while converting to string.
 *
 * @return is the string representation of input float value.
 */
std::string toString(const float pVal, const int pPrecision = 2);

/* Get a vertex buffer object for quad that spans the screen
 */
gl::GLuint screenQuadVBO(const int pWindowId);

/* Get a vertex array object that uses screenQuadVBO
 *
 * This vertex array object when bound and rendered, basically
 * draws a rectangle over the entire screen with standard
 * texture coordinates. Use of this vao would be as follows
 *
 *     `glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);`
 */
gl::GLuint screenQuadVAO(const int pWindowId);

/* Print glm::mat4 to std::cout stream */
std::ostream& operator<<(std::ostream&, const glm::mat4&);

/* get the point of the surface of track ball */
glm::vec3 trackballPoint(const float pX, const float pY,
                         const float pWidth, const float pHeight);

namespace forge
{
namespace opengl
{

typedef unsigned int    uint;
typedef unsigned short  ushort;
typedef unsigned char   uchar;

class ShaderProgram {
    private:
        gl::GLuint mVertex;
        gl::GLuint mFragment;
        gl::GLuint mGeometry;
        gl::GLuint mProgram;

    public:
        ShaderProgram(const char* pVertShaderSrc,
                      const char* pFragShaderSrc,
                      const char* pGeomShaderSrc=NULL);

        ~ShaderProgram();

        gl::GLuint getProgramId() const;

        gl::GLuint getUniformLocation(const char* pAttributeName);
        gl::GLuint getUniformBlockIndex(const char* pAttributeName);
        gl::GLuint getAttributeLocation(const char* pAttributeName);

        void bind();
        void unbind();
};

/* Basic renderable class
 *
 * Any object that is renderable to a window should inherit from this
 * class.
 */
class AbstractRenderable {
    protected:
        /* OpenGL buffer objects */
        gl::GLuint  mVBO;
        gl::GLuint  mCBO;
        gl::GLuint  mABO;
        size_t      mVBOSize;
        size_t      mCBOSize;
        size_t      mABOSize;
        gl::GLfloat mColor[4];
        gl::GLfloat mRange[6];
        std::string mLegend;
        bool        mIsPVCOn;
        bool        mIsPVAOn;

    public:
        /* Getter functions for OpenGL buffer objects
         * identifiers and their size in bytes
         *
         *  vbo is for vertices
         *  cbo is for colors of those vertices
         *  abo is for alpha values for those vertices
         */
        gl::GLuint vbo() const { return mVBO; }
        gl::GLuint cbo() { mIsPVCOn = true; return mCBO; }
        gl::GLuint abo() { mIsPVAOn = true; return mABO; }
        size_t vboSize() const { return mVBOSize; }
        size_t cboSize() const { return mCBOSize; }
        size_t aboSize() const { return mABOSize; }

        /* Set color for rendering
         */
        void setColor(const float pRed, const float pGreen,
                      const float pBlue, const float pAlpha) {
            mColor[0] = clampTo01(pRed);
            mColor[1] = clampTo01(pGreen);
            mColor[2] = clampTo01(pBlue);
            mColor[3] = clampTo01(pAlpha);
        }

        /* Get renderable solid color
         */
        void getColor(float& pRed, float& pGreen, float& pBlue, float& pAlpha) {
            pRed    = mColor[0];
            pGreen  = mColor[1];
            pBlue   = mColor[2];
            pAlpha  = mColor[3];
        }

        /* Set legend for rendering
         */
        void setLegend(const char* pLegend) {
            mLegend = std::string(pLegend);
        }

        /* Get legend string
         */
        const std::string& legend() const {
            return mLegend;
        }

        /* Set 3d world coordinate ranges
         *
         * This method is mostly used for charts and related renderables
         */
        void setRanges(const float pMinX, const float pMaxX,
                       const float pMinY, const float pMaxY,
                       const float pMinZ, const float pMaxZ) {
            mRange[0] = pMinX; mRange[1] = pMaxX;
            mRange[2] = pMinY; mRange[3] = pMaxY;
            mRange[4] = pMinZ; mRange[5] = pMaxZ;
        }

        /* virtual function to set colormap, a derviced class might
         * use it or ignore it if it doesnt have a need for color maps.
         */
        virtual void setColorMapUBOParams(const gl::GLuint pUBO, const gl::GLuint pSize) {
        }

        /* render is a pure virtual function.
         *
         * @pWindowId is the window identifier
         * @pX is the X coordinate at which the currently bound viewport begins.
         * @pX is the Y coordinate at which the currently bound viewport begins.
         * @pViewPortWidth is the width of the currently bound viewport.
         * @pViewPortHeight is the height of the currently bound viewport.
         *
         * Any concrete class that inherits AbstractRenderable class needs to
         * implement this method to render their OpenGL objects to
         * the currently bound viewport of the Window bearing identifier pWindowId.
         *
         * @return nothing.
         */
        virtual void render(const int pWindowId,
                            const int pX, const int pY, const int pVPW, const int pVPH,
                            const glm::mat4 &pView, const glm::mat4 &pOrient) = 0;
};

}
}
<commit_msg>Add constructor to AbstractRenderable Class<commit_after>/*******************************************************
 * Copyright (c) 2015-2019, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once

#include <fg/defines.h>
#include <fg/exception.h>
#include <err_common.hpp>

#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>

#include <vector>
#include <iterator>

static const float BLACK[]   = {0.0f    , 0.0f    , 0.0f    , 1.0f};
static const float GRAY[]    = {0.85f   , 0.85f   , 0.85f   , 1.0f};
static const float WHITE[]   = {1.0f    , 1.0f    , 1.0f    , 1.0f};
static const float AF_BLUE[] = {0.0588f , 0.1137f , 0.2745f , 1.0f};
static const glm::mat4 IDENTITY(1.0f);

/* clamp the float to [0-1] range
 *
 * @pValue is the value to be clamped
 */
float clampTo01(const float pValue);

/* Convert forge type enum to OpenGL enum for GL_* type
 *
 * @pValue is the forge type enum
 *
 * @return GL_* typedef for data type
 */
gl::GLenum dtype2gl(const forge::dtype pValue);

/* Convert forge channel format enum to OpenGL enum to indicate color component layout
 *
 * @pValue is the forge type enum
 *
 * @return OpenGL enum indicating color component layout
 */
gl::GLenum ctype2gl(const forge::ChannelFormat pMode);

/* Convert forge channel format enum to OpenGL enum to indicate color component layout
 *
 * This function is used to group color component layout formats based
 * on number of components.
 *
 * @pValue is the forge type enum
 *
 * @return OpenGL enum indicating color component layout
 */
gl::GLenum ictype2gl(const forge::ChannelFormat pMode);

/* Create OpenGL buffer object
 *
 * @pTarget should be either GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER
 * @pSize is the size of the data in bytes
 * @pPtr is the pointer to host data. This can be NULL
 * @pUsage should be either GL_STATIC_DRAW or GL_DYNAMIC_DRAW
 *
 * @return OpenGL buffer object identifier
 */
template<typename T>
gl::GLuint createBuffer(gl::GLenum pTarget, size_t pSize, const T* pPtr, gl::GLenum pUsage)
{
    gl::GLuint retVal = 0;
    gl::glGenBuffers(1, &retVal);
    gl::glBindBuffer(pTarget, retVal);
    gl::glBufferData(pTarget, pSize*sizeof(T), pPtr, pUsage);
    gl::glBindBuffer(pTarget, 0);
    return retVal;
}

#ifdef OS_WIN
/* Get the paths to font files in Windows system directory
 *
 * @pFiles is the output vector to which font file paths are appended to.
 * @pDir is the directory from which font files are looked up
 * @pExt is the target font file extension we are looking for.
 */
void getFontFilePaths(std::vector<std::string>& pFiles,
                      const std::string& pDir,
                      const std::string& pExt);
#endif

/* Convert float value to string with given precision
 *
 * @pVal is the float value whose string representation is requested.
 * @pPrecision is the precision of the float used while converting to string.
 *
 * @return is the string representation of input float value.
 */
std::string toString(const float pVal, const int pPrecision = 2);

/* Get a vertex buffer object for quad that spans the screen
 */
gl::GLuint screenQuadVBO(const int pWindowId);

/* Get a vertex array object that uses screenQuadVBO
 *
 * This vertex array object when bound and rendered, basically
 * draws a rectangle over the entire screen with standard
 * texture coordinates. Use of this vao would be as follows
 *
 *     `glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);`
 */
gl::GLuint screenQuadVAO(const int pWindowId);

/* Print glm::mat4 to std::cout stream */
std::ostream& operator<<(std::ostream&, const glm::mat4&);

/* get the point of the surface of track ball */
glm::vec3 trackballPoint(const float pX, const float pY,
                         const float pWidth, const float pHeight);

namespace forge
{
namespace opengl
{

typedef unsigned int    uint;
typedef unsigned short  ushort;
typedef unsigned char   uchar;

class ShaderProgram {
    private:
        gl::GLuint mVertex;
        gl::GLuint mFragment;
        gl::GLuint mGeometry;
        gl::GLuint mProgram;

    public:
        ShaderProgram(const char* pVertShaderSrc,
                      const char* pFragShaderSrc,
                      const char* pGeomShaderSrc=NULL);

        ~ShaderProgram();

        gl::GLuint getProgramId() const;

        gl::GLuint getUniformLocation(const char* pAttributeName);
        gl::GLuint getUniformBlockIndex(const char* pAttributeName);
        gl::GLuint getAttributeLocation(const char* pAttributeName);

        void bind();
        void unbind();
};

/* Basic renderable class
 *
 * Any object that is renderable to a window should inherit from this
 * class.
 */
class AbstractRenderable {
    protected:
        /* OpenGL buffer objects */
        gl::GLuint  mVBO;
        gl::GLuint  mCBO;
        gl::GLuint  mABO;
        size_t      mVBOSize;
        size_t      mCBOSize;
        size_t      mABOSize;
        gl::GLfloat mColor[4];
        gl::GLfloat mRange[6];
        std::string mLegend;
        bool        mIsPVCOn;
        bool        mIsPVAOn;

        AbstractRenderable():
            mVBO(0), mCBO(0), mABO(0),
            mVBOSize(0), mCBOSize(0), mABOSize(0),
            mIsPVCOn(0), mIsPVAOn(0)
        {
            mColor[0] = 0;
            mColor[1] = 0;
            mColor[2] = 0;
            mColor[3] = 0;

            mRange[0] = 0;
            mRange[1] = 0;
            mRange[2] = 0;
            mRange[3] = 0;
            mRange[4] = 0;
            mRange[5] = 0;
        }

    public:
        /* Getter functions for OpenGL buffer objects
         * identifiers and their size in bytes
         *
         *  vbo is for vertices
         *  cbo is for colors of those vertices
         *  abo is for alpha values for those vertices
         */
        gl::GLuint vbo() const { return mVBO; }
        gl::GLuint cbo() { mIsPVCOn = true; return mCBO; }
        gl::GLuint abo() { mIsPVAOn = true; return mABO; }
        size_t vboSize() const { return mVBOSize; }
        size_t cboSize() const { return mCBOSize; }
        size_t aboSize() const { return mABOSize; }

        /* Set color for rendering
         */
        void setColor(const float pRed, const float pGreen,
                      const float pBlue, const float pAlpha) {
            mColor[0] = clampTo01(pRed);
            mColor[1] = clampTo01(pGreen);
            mColor[2] = clampTo01(pBlue);
            mColor[3] = clampTo01(pAlpha);
        }

        /* Get renderable solid color
         */
        void getColor(float& pRed, float& pGreen, float& pBlue, float& pAlpha) {
            pRed    = mColor[0];
            pGreen  = mColor[1];
            pBlue   = mColor[2];
            pAlpha  = mColor[3];
        }

        /* Set legend for rendering
         */
        void setLegend(const char* pLegend) {
            mLegend = std::string(pLegend);
        }

        /* Get legend string
         */
        const std::string& legend() const {
            return mLegend;
        }

        /* Set 3d world coordinate ranges
         *
         * This method is mostly used for charts and related renderables
         */
        void setRanges(const float pMinX, const float pMaxX,
                       const float pMinY, const float pMaxY,
                       const float pMinZ, const float pMaxZ) {
            mRange[0] = pMinX; mRange[1] = pMaxX;
            mRange[2] = pMinY; mRange[3] = pMaxY;
            mRange[4] = pMinZ; mRange[5] = pMaxZ;
        }

        /* virtual function to set colormap, a derviced class might
         * use it or ignore it if it doesnt have a need for color maps.
         */
        virtual void setColorMapUBOParams(const gl::GLuint pUBO, const gl::GLuint pSize) {
        }

        /* render is a pure virtual function.
         *
         * @pWindowId is the window identifier
         * @pX is the X coordinate at which the currently bound viewport begins.
         * @pX is the Y coordinate at which the currently bound viewport begins.
         * @pViewPortWidth is the width of the currently bound viewport.
         * @pViewPortHeight is the height of the currently bound viewport.
         *
         * Any concrete class that inherits AbstractRenderable class needs to
         * implement this method to render their OpenGL objects to
         * the currently bound viewport of the Window bearing identifier pWindowId.
         *
         * @return nothing.
         */
        virtual void render(const int pWindowId,
                            const int pX, const int pY, const int pVPW, const int pVPH,
                            const glm::mat4 &pView, const glm::mat4 &pOrient) = 0;
};

}
}
<|endoftext|>


<commit_before>#include "hext/node-util.h"

namespace hext {

unsigned int GetNodePositionWithinParent(const GumboNode * node)
{
  if( !node )
    return 0;

  const GumboNode * parent = node->parent;

  if( !parent || parent->type != GUMBO_NODE_ELEMENT )
    return 0;

  unsigned int pos = 0;
  const GumboVector& child_nodes = parent->v.element.children;
  // We only have to traverse up to node->index_within_parent, and not the
  // whole GumboVector.
  for(unsigned int i = 0; i <= node->index_within_parent; ++i)
  {
    assert(i < child_nodes.length);
    const GumboNode * child =
      static_cast<const GumboNode *>(child_nodes.data[i]);

    if( child && child->type == GUMBO_NODE_ELEMENT )
      ++pos;

    if( node == child )
      return pos;
  }

  return 0;
}

std::string GetNodeText(const GumboNode * node)
{
  return TrimAndCollapseWs(GetNodeRawText(node));
}

std::string GetNodeRawText(const GumboNode * node)
{
  if( !node || node->type != GUMBO_NODE_ELEMENT )
    return "";

  std::string inner_text;

  const GumboVector * children = &node->v.element.children;
  for(unsigned int i = 0; i < children->length; ++i)
  {
    const GumboNode * child_node =
      static_cast<const GumboNode *>(children->data[i]);
    assert(child_node != nullptr);

    if( child_node->type == GUMBO_NODE_TEXT )
    {
      const GumboText * node_text = &child_node->v.text;
      assert(node_text != nullptr);
      assert(node_text->text != nullptr);
      inner_text.push_back(' ');
      inner_text.append(node_text->text);
    }
    else if( child_node->type == GUMBO_NODE_ELEMENT )
    {
      inner_text.push_back(' ');
      inner_text.append(GetNodeRawText(child_node));
    }
  }

  return inner_text;
}

std::string GetNodeInnerHtml(const GumboNode * node)
{
  if( !node || node->type != GUMBO_NODE_ELEMENT )
    return "";

  const GumboStringPiece& b = node->v.element.original_tag;
  const GumboStringPiece& e = node->v.element.original_end_tag;

  if( b.data != nullptr && b.length > 0 &&
      e.data != nullptr && e.length > 0 )
  {
    const char * inner_begin = b.data + b.length;
    size_t length = std::distance(inner_begin, e.data);
    return std::string(inner_begin, length);
  }

  return "";
}

} // hext

<commit_msg>GetNodeInnerHtml: check if beginning is actually at a lower address than end<commit_after>#include "hext/node-util.h"

namespace hext {

unsigned int GetNodePositionWithinParent(const GumboNode * node)
{
  if( !node )
    return 0;

  const GumboNode * parent = node->parent;

  if( !parent || parent->type != GUMBO_NODE_ELEMENT )
    return 0;

  unsigned int pos = 0;
  const GumboVector& child_nodes = parent->v.element.children;
  // We only have to traverse up to node->index_within_parent, and not the
  // whole GumboVector.
  for(unsigned int i = 0; i <= node->index_within_parent; ++i)
  {
    assert(i < child_nodes.length);
    const GumboNode * child =
      static_cast<const GumboNode *>(child_nodes.data[i]);

    if( child && child->type == GUMBO_NODE_ELEMENT )
      ++pos;

    if( node == child )
      return pos;
  }

  return 0;
}

std::string GetNodeText(const GumboNode * node)
{
  return TrimAndCollapseWs(GetNodeRawText(node));
}

std::string GetNodeRawText(const GumboNode * node)
{
  if( !node || node->type != GUMBO_NODE_ELEMENT )
    return "";

  std::string inner_text;

  const GumboVector * children = &node->v.element.children;
  for(unsigned int i = 0; i < children->length; ++i)
  {
    const GumboNode * child_node =
      static_cast<const GumboNode *>(children->data[i]);
    assert(child_node != nullptr);

    if( child_node->type == GUMBO_NODE_TEXT )
    {
      const GumboText * node_text = &child_node->v.text;
      assert(node_text != nullptr);
      assert(node_text->text != nullptr);
      inner_text.push_back(' ');
      inner_text.append(node_text->text);
    }
    else if( child_node->type == GUMBO_NODE_ELEMENT )
    {
      inner_text.push_back(' ');
      inner_text.append(GetNodeRawText(child_node));
    }
  }

  return inner_text;
}

std::string GetNodeInnerHtml(const GumboNode * node)
{
  if( !node || node->type != GUMBO_NODE_ELEMENT )
    return "";

  const GumboStringPiece& b = node->v.element.original_tag;
  const GumboStringPiece& e = node->v.element.original_end_tag;

  if( b.data && b.length > 0 &&
      e.data && e.length > 0 &&
      ( b.data + b.length ) < e.data )
  {
    const char * inner_begin = b.data + b.length;
    size_t length = std::distance(inner_begin, e.data);
    return std::string(inner_begin, length);
  }

  return "";
}

} // hext

<|endoftext|>


<commit_before>//===---------------------------- cxa_guard.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "__cxxabi_config.h"

#include "abort_message.h"
#include <__threading_support>

#include <stdint.h>

/*
    This implementation must be careful to not call code external to this file
    which will turn around and try to call __cxa_guard_acquire reentrantly.
    For this reason, the headers of this file are as restricted as possible.
    Previous implementations of this code for __APPLE__ have used
    std::__libcpp_mutex_lock and the abort_message utility without problem. This
    implementation also uses std::__libcpp_condvar_wait which has tested
    to not be a problem.
*/

namespace __cxxabiv1
{

namespace
{

#ifdef __arm__
// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
// be statically initialized to 0.
typedef uint32_t guard_type;

inline void set_initialized(guard_type* guard_object) {
    *guard_object |= 1;
}

// Test the lowest bit.
inline bool is_initialized(guard_type* guard_object) {
    return (*guard_object) & 1;
}

#else
typedef uint64_t guard_type;

void set_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    *initialized = 1;
}

bool is_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    return *initialized;
}
#endif

#ifndef _LIBCXXABI_HAS_NO_THREADS
std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
#endif

#if defined(__APPLE__) && !defined(__arm__)

typedef uint32_t lock_type;

#if __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x >> 32);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = static_cast<uint64_t>(y) << 32;
}

#else  // __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = y;
}

#endif  // __LITTLE_ENDIAN__

#else  // !__APPLE__ || __arm__

typedef bool lock_type;

#if !defined(__arm__)
static_assert(std::is_same<guard_type, uint64_t>::value, "");

inline lock_type get_lock(uint64_t x)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline void set_lock(uint64_t& x, lock_type y)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}
#else // defined(__arm__)
static_assert(std::is_same<guard_type, uint32_t>::value, "");

inline lock_type get_lock(uint32_t x)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline void set_lock(uint32_t& x, lock_type y)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

#endif // !defined(__arm__)

#endif  // __APPLE__ && !__arm__

}  // unnamed namespace

extern "C"
{

#ifndef _LIBCXXABI_HAS_NO_THREADS
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
    if (std::__libcpp_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to acquire mutex");
    int result = !is_initialized(guard_object);
    if (result)
    {
#if defined(__APPLE__) && !defined(__arm__)
        // This is a special-case pthread dependency for Mac. We can't pull this
        // out into libcxx's threading API (__threading_support) because not all
        // supported Mac environments provide this function (in pthread.h). To
        // make it possible to build/use libcxx in those environments, we have to
        // keep this pthread dependency local to libcxxabi. If there is some
        // convenient way to detect precisely when pthread_mach_thread_np is
        // available in a given Mac environment, it might still be possible to
        // bury this dependency in __threading_support.
        #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
           const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
        #else
           #error "How do I pthread_mach_thread_np()?"
        #endif
        lock_type lock = get_lock(*guard_object);
        if (lock)
        {
            // if this thread set lock for this same guard_object, abort
            if (lock == id)
                abort_message("__cxa_guard_acquire detected deadlock");
            do
            {
                if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
                    abort_message("__cxa_guard_acquire condition variable wait failed");
                lock = get_lock(*guard_object);
            } while (lock);
            result = !is_initialized(guard_object);
            if (result)
                set_lock(*guard_object, id);
        }
        else
            set_lock(*guard_object, id);
#else  // !__APPLE__ || __arm__
        while (get_lock(*guard_object))
            if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
                abort_message("__cxa_guard_acquire condition variable wait failed");
        result = !is_initialized(guard_object);
        if (result)
            set_lock(*guard_object, true);
#endif  // !__APPLE__ || __arm__
    }
    if (std::__libcpp_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_acquire failed to release mutex");
    return result;
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
    if (std::__libcpp_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_release failed to acquire mutex");
    *guard_object = 0;
    set_initialized(guard_object);
    if (std::__libcpp_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_release failed to release mutex");
    if (std::__libcpp_condvar_broadcast(&guard_cv))
        abort_message("__cxa_guard_release failed to broadcast condition variable");
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
    if (std::__libcpp_mutex_lock(&guard_mut))
        abort_message("__cxa_guard_abort failed to acquire mutex");
    *guard_object = 0;
    if (std::__libcpp_mutex_unlock(&guard_mut))
        abort_message("__cxa_guard_abort failed to release mutex");
    if (std::__libcpp_condvar_broadcast(&guard_cv))
        abort_message("__cxa_guard_abort failed to broadcast condition variable");
}

#else // _LIBCXXABI_HAS_NO_THREADS

_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
    return !is_initialized(guard_object);
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
    *guard_object = 0;
    set_initialized(guard_object);
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
    *guard_object = 0;
}

#endif // !_LIBCXXABI_HAS_NO_THREADS

}  // extern "C"

}  // __cxxabiv1
<commit_msg>Create RAII lock guard for global initialization lock.<commit_after>//===---------------------------- cxa_guard.cpp ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "__cxxabi_config.h"

#include "abort_message.h"
#include <__threading_support>

#include <stdint.h>

/*
    This implementation must be careful to not call code external to this file
    which will turn around and try to call __cxa_guard_acquire reentrantly.
    For this reason, the headers of this file are as restricted as possible.
    Previous implementations of this code for __APPLE__ have used
    std::__libcpp_mutex_lock and the abort_message utility without problem. This
    implementation also uses std::__libcpp_condvar_wait which has tested
    to not be a problem.
*/

namespace __cxxabiv1
{

namespace
{

#ifdef __arm__
// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
// be statically initialized to 0.
typedef uint32_t guard_type;

inline void set_initialized(guard_type* guard_object) {
    *guard_object |= 1;
}

// Test the lowest bit.
inline bool is_initialized(guard_type* guard_object) {
    return (*guard_object) & 1;
}

#else
typedef uint64_t guard_type;

void set_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    *initialized = 1;
}

bool is_initialized(guard_type* guard_object) {
    char* initialized = (char*)guard_object;
    return *initialized;
}
#endif

enum class OnRelease : char { UNLOCK, UNLOCK_AND_BROADCAST };

struct GlobalMutexGuard {
  explicit GlobalMutexGuard(const char* calling_func, OnRelease on_release)
      : calling_func(calling_func), on_release(on_release) {
#ifndef _LIBCXXABI_HAS_NO_THREADS
    if (std::__libcpp_mutex_lock(&guard_mut))
      abort_message("%s failed to acquire mutex", calling_func);
#endif
  }

  ~GlobalMutexGuard() {
#ifndef _LIBCXXABI_HAS_NO_THREADS
    if (std::__libcpp_mutex_unlock(&guard_mut))
      abort_message("%s failed to release mutex", calling_func);
    if (on_release == OnRelease::UNLOCK_AND_BROADCAST) {
      if (std::__libcpp_condvar_broadcast(&guard_cv))
        abort_message("%s failed to broadcast condition variable",
                      calling_func);
    }
#endif
  }

  void wait_for_signal() {
#ifndef _LIBCXXABI_HAS_NO_THREADS
    if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
      abort_message("%s condition variable wait failed", calling_func);
#endif
  }

private:
  GlobalMutexGuard(GlobalMutexGuard const&) = delete;
  GlobalMutexGuard& operator=(GlobalMutexGuard const&) = delete;

  const char* const calling_func;
  OnRelease on_release;

#ifndef _LIBCXXABI_HAS_NO_THREADS
  static std::__libcpp_mutex_t guard_mut;
  static std::__libcpp_condvar_t guard_cv;
#endif
};

#ifndef _LIBCXXABI_HAS_NO_THREADS
std::__libcpp_mutex_t GlobalMutexGuard::guard_mut = _LIBCPP_MUTEX_INITIALIZER;
std::__libcpp_condvar_t GlobalMutexGuard::guard_cv =
    _LIBCPP_CONDVAR_INITIALIZER;
#endif

#if defined(__APPLE__) && !defined(__arm__)

typedef uint32_t lock_type;

#if __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x >> 32);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = static_cast<uint64_t>(y) << 32;
}

#else  // __LITTLE_ENDIAN__

inline
lock_type
get_lock(uint64_t x)
{
    return static_cast<lock_type>(x);
}

inline
void
set_lock(uint64_t& x, lock_type y)
{
    x = y;
}

#endif  // __LITTLE_ENDIAN__

#else  // !__APPLE__ || __arm__

typedef bool lock_type;

#if !defined(__arm__)
static_assert(std::is_same<guard_type, uint64_t>::value, "");

inline lock_type get_lock(uint64_t x)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline void set_lock(uint64_t& x, lock_type y)
{
    union
    {
        uint64_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}
#else // defined(__arm__)
static_assert(std::is_same<guard_type, uint32_t>::value, "");

inline lock_type get_lock(uint32_t x)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {x};
    return f.lock[1] != 0;
}

inline void set_lock(uint32_t& x, lock_type y)
{
    union
    {
        uint32_t guard;
        uint8_t lock[2];
    } f = {0};
    f.lock[1] = y;
    x = f.guard;
}

#endif // !defined(__arm__)

#endif  // __APPLE__ && !__arm__

}  // unnamed namespace

extern "C"
{

_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
  GlobalMutexGuard gmutex("__cxa_guard_acquire", OnRelease::UNLOCK);
  int result = !is_initialized(guard_object);
  if (result) {
#if defined(_LIBCXXABI_HAS_NO_THREADS)
    // nothing to do
#elif defined(__APPLE__) && !defined(__arm__)
// This is a special-case pthread dependency for Mac. We can't pull this
// out into libcxx's threading API (__threading_support) because not all
// supported Mac environments provide this function (in pthread.h). To
// make it possible to build/use libcxx in those environments, we have to
// keep this pthread dependency local to libcxxabi. If there is some
// convenient way to detect precisely when pthread_mach_thread_np is
// available in a given Mac environment, it might still be possible to
// bury this dependency in __threading_support.
#ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
    const lock_type id =
        pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
#else
#error "How do I pthread_mach_thread_np()?"
#endif
    lock_type lock = get_lock(*guard_object);
    if (lock) {
      // if this thread set lock for this same guard_object, abort
      if (lock == id)
        abort_message("__cxa_guard_acquire detected deadlock");
      do {
        gmutex.wait_for_signal();
        lock = get_lock(*guard_object);
      } while (lock);
      result = !is_initialized(guard_object);
      if (result)
        set_lock(*guard_object, id);
    } else
      set_lock(*guard_object, id);
#else  // !__APPLE__ || __arm__
    while (get_lock(*guard_object)) {
      gmutex.wait_for_signal();
    }
    result = !is_initialized(guard_object);
    if (result)
      set_lock(*guard_object, true);
#endif  // !__APPLE__ || __arm__
  }
  return result;
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
  GlobalMutexGuard gmutex("__cxa_guard_release",
                          OnRelease::UNLOCK_AND_BROADCAST);
  *guard_object = 0;
  set_initialized(guard_object);
}

_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
  GlobalMutexGuard gmutex("__cxa_guard_abort", OnRelease::UNLOCK);
  *guard_object = 0;
}

}  // extern "C"

}  // __cxxabiv1
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// mapnik
#include <mapnik/formatting/text.hpp>
#include <mapnik/expression_string.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/text_properties.hpp>
#include <mapnik/processed_text.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/value_types.hpp>

// boost
#include <boost/property_tree/ptree.hpp>
#include <boost/make_shared.hpp>

namespace mapnik
{
namespace formatting
{

using boost::property_tree::ptree;

void text_node::to_xml(ptree &xml) const
{
    ptree &new_node = xml.push_back(ptree::value_type(
                                        "<xmltext>", ptree()))->second;
    new_node.put_value(to_expression_string(*text_));
}

node_ptr text_node::from_xml(xml_node const& xml)
{
    return boost::make_shared<text_node>(xml.get_value<expression_ptr>());
}

void text_node::apply(char_properties const& p, feature_impl const& feature, processed_text &output) const
{
    mapnik::value_unicode_string text_str = boost::apply_visitor(evaluate<feature_impl,value_type>(feature), *text_).to_unicode();
    if (p.text_transform == UPPERCASE)
    {
        text_str = text_str.toUpper();
    }
    else if (p.text_transform == LOWERCASE)
    {
        text_str = text_str.toLower();
    }
    else if (p.text_transform == CAPITALIZE)
    {
        text_str = text_str.toTitle(NULL);
    }
    if (text_str.length() > 0) {
        output.push_back(p, text_str);
    }
}

void text_node::add_expressions(expression_set &output) const
{
    if (text_) output.insert(text_);
}

void text_node::set_text(expression_ptr text)
{
    text_ = text;
}

expression_ptr text_node::get_text() const
{
    return text_;
}

} //ns formatting
} //ns mapnik
<commit_msg>gracefully handle when icu is built without BreakIterator support: -DUCONFIG_NO_BREAK_ITERATION=1<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// mapnik
#include <mapnik/formatting/text.hpp>
#include <mapnik/expression_string.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/text_properties.hpp>
#include <mapnik/processed_text.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/value_types.hpp>

// boost
#include <boost/property_tree/ptree.hpp>
#include <boost/make_shared.hpp>

namespace mapnik
{
namespace formatting
{

using boost::property_tree::ptree;

void text_node::to_xml(ptree &xml) const
{
    ptree &new_node = xml.push_back(ptree::value_type(
                                        "<xmltext>", ptree()))->second;
    new_node.put_value(to_expression_string(*text_));
}

node_ptr text_node::from_xml(xml_node const& xml)
{
    return boost::make_shared<text_node>(xml.get_value<expression_ptr>());
}

void text_node::apply(char_properties const& p, feature_impl const& feature, processed_text &output) const
{
    mapnik::value_unicode_string text_str = boost::apply_visitor(evaluate<feature_impl,value_type>(feature), *text_).to_unicode();
    if (p.text_transform == UPPERCASE)
    {
        text_str = text_str.toUpper();
    }
    else if (p.text_transform == LOWERCASE)
    {
        text_str = text_str.toLower();
    }
#if !UCONFIG_NO_BREAK_ITERATION
    else if (p.text_transform == CAPITALIZE)
    {
        // note: requires BreakIterator support in ICU which is optional
        text_str = text_str.toTitle(NULL);
    }
#endif
    if (text_str.length() > 0) {
        output.push_back(p, text_str);
    }
}

void text_node::add_expressions(expression_set &output) const
{
    if (text_) output.insert(text_);
}

void text_node::set_text(expression_ptr text)
{
    text_ = text;
}

expression_ptr text_node::get_text() const
{
    return text_;
}

} //ns formatting
} //ns mapnik
<|endoftext|>


<commit_before>/**
 * @file sqlite.cpp
 * @brief SQLite DB access layer
 *
 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"

#ifdef USE_SQLITE
namespace mega {

SqliteDbAccess::SqliteDbAccess(const LocalPath& rootPath)
  : mRootPath(rootPath)
{
}

SqliteDbAccess::~SqliteDbAccess()
{
}

LocalPath SqliteDbAccess::databasePath(const FileSystemAccess& fsAccess,
                                       const string& name,
                                       const int version) const
{
    ostringstream osstream;

    osstream << "megaclient_statecache"
             << version
             << "_"
             << name
             << ".db";

    LocalPath path = mRootPath;

    path.appendWithSeparator(
      LocalPath::fromPath(osstream.str(), fsAccess),
      false);

    return path;
}

SqliteDbTable* SqliteDbAccess::open(PrnGen &rng, FileSystemAccess& fsAccess, const string& name, const int flags)
{
    auto dbPath = databasePath(fsAccess, name, DB_VERSION);
    auto upgraded = true;

    {
        auto legacyPath = databasePath(fsAccess, name, LEGACY_DB_VERSION);
        auto fileAccess = fsAccess.newfileaccess();

        if (fileAccess->fopen(legacyPath))
        {
            LOG_debug << "Found legacy database at: " << legacyPath.toPath(fsAccess);

            if (currentDbVersion == LEGACY_DB_VERSION)
            {
                LOG_debug << "Using a legacy database.";
                dbPath = std::move(legacyPath);
                upgraded = false;
            }
            else if ((flags & DB_OPEN_FLAG_RECYCLE))
            {
                LOG_debug << "Trying to recycle a legacy database.";

                if (fsAccess.renamelocal(legacyPath, dbPath, false))
                {
                    auto suffix = LocalPath::fromPath("-shm", fsAccess);
                    auto from = legacyPath + suffix;
                    auto to = dbPath + suffix;

                    fsAccess.renamelocal(from, to);

                    suffix = LocalPath::fromPath("-wal", fsAccess);
                    from = legacyPath + suffix;
                    to = dbPath + suffix;

                    fsAccess.renamelocal(from, to);

                    LOG_debug << "Legacy database recycled.";
                }
                else
                {
                    LOG_debug << "Unable to recycle database, deleting...";
                    fsAccess.unlinklocal(legacyPath);
                }
            }
            else
            {
                LOG_debug << "Deleting outdated legacy database.";
                fsAccess.unlinklocal(legacyPath);
            }
        }
    }

    if (upgraded)
    {
        LOG_debug << "Using an upgraded DB: " << dbPath.toPath(fsAccess);
        currentDbVersion = DB_VERSION;
    }

    const string dbPathStr = dbPath.toPath(fsAccess);
    sqlite3* db;
    int result = sqlite3_open(dbPathStr.c_str(), &db);

    if (result)
    {
        if (db)
        {
            sqlite3_close(db);
        }

        return nullptr;
    }

#if !(TARGET_OS_IPHONE)
    result = sqlite3_exec(db, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr);
    if (result)
    {
        sqlite3_close(db);
        return nullptr;
    }
#endif /* ! TARGET_OS_IPHONE */

    const char* sql =
      "CREATE TABLE IF NOT EXISTS statecache ( "
      "    id INTEGER PRIMARY KEY ASC NOT NULL, "
      "    content BLOB NOT NULL "
      ");";

    result = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
    if (result)
    {
        sqlite3_close(db);
        return nullptr;
    }

    const char* tableVar = "CREATE TABLE IF NOT EXISTS vars(name text PRIMARY KEY NOT NULL, value BLOB)";
    result = sqlite3_exec(db, tableVar, nullptr, nullptr, nullptr);
    if (result)
    {
        sqlite3_close(db);
        return nullptr;
    }

    return new SqliteDbTable(rng,
                             db,
                             fsAccess,
                             dbPathStr,
                             (flags & DB_OPEN_FLAG_TRANSACTED) > 0);
}

bool SqliteDbAccess::probe(FileSystemAccess& fsAccess, const string& name) const
{
    auto fileAccess = fsAccess.newfileaccess();

    LocalPath dbPath = databasePath(fsAccess, name, DB_VERSION);

    if (fileAccess->isfile(dbPath))
    {
        return true;
    }

    dbPath = databasePath(fsAccess, name, LEGACY_DB_VERSION);

    return fileAccess->isfile(dbPath);
}

const LocalPath& SqliteDbAccess::rootPath() const
{
    return mRootPath;
}

SqliteDbTable::SqliteDbTable(PrnGen &rng, sqlite3* db, FileSystemAccess &fsAccess, const string &path, const bool checkAlwaysTransacted)
  : DbTable(rng, checkAlwaysTransacted)
  , db(db)
  , pStmt(nullptr)
  , dbfile(path)
  , fsaccess(&fsAccess)
{
}

SqliteDbTable::~SqliteDbTable()
{
    resetCommitter();

    if (!db)
    {
        return;
    }

    sqlite3_finalize(pStmt);

    if (inTransaction())
    {
        abort();
    }

    sqlite3_close(db);
    LOG_debug << "Database closed " << dbfile;
}

bool SqliteDbTable::inTransaction() const
{
    return sqlite3_get_autocommit(db) == 0;
}

LocalPath SqliteDbTable::dbFile() const
{
    return LocalPath::fromPath(dbfile, *fsaccess);
}

// set cursor to first record
void SqliteDbTable::rewind()
{
    if (!db)
    {
        return;
    }

    int result;

    if (pStmt)
    {
        result = sqlite3_reset(pStmt);
    }
    else
    {
        result = sqlite3_prepare(db, "SELECT id, content FROM statecache", -1, &pStmt, NULL);
    }

    if (result != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(result));
        LOG_err << "Unable to rewind database: " << dbfile << err;
        assert(!"Unable to rewind database.");
    }
}

// retrieve next record through cursor
bool SqliteDbTable::next(uint32_t* index, string* data)
{
    if (!db)
    {
        return false;
    }

    if (!pStmt)
    {
        return false;
    }

    int rc = sqlite3_step(pStmt);

    if (rc != SQLITE_ROW)
    {
        sqlite3_finalize(pStmt);
        pStmt = NULL;

        if (rc != SQLITE_DONE)
        {
            string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
            LOG_err << "Unable to get next record from database: " << dbfile << err;
            assert(!"Unable to get next record from database.");
        }

        return false;
    }

    *index = sqlite3_column_int(pStmt, 0);

    data->assign((char*)sqlite3_column_blob(pStmt, 1), sqlite3_column_bytes(pStmt, 1));

    return true;
}

// retrieve record by index
bool SqliteDbTable::get(uint32_t index, string* data)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    sqlite3_stmt *stmt;
    int rc;

    rc = sqlite3_prepare(db, "SELECT content FROM statecache WHERE id = ?", -1, &stmt, NULL);
    if (rc == SQLITE_OK)
    {
        rc = sqlite3_bind_int(stmt, 1, index);
        if (rc == SQLITE_OK)
        {
            rc = sqlite3_step(stmt);
            if (rc == SQLITE_ROW)
            {
                data->assign((char*)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
            }
        }
    }

    sqlite3_finalize(stmt);

    if (rc != SQLITE_DONE && rc != SQLITE_ROW)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to get record from database: " << dbfile << err;
        assert(!"Unable to get record from database.");
    }

    return rc == SQLITE_ROW;
}

// add/update record by index
bool SqliteDbTable::put(uint32_t index, char* data, unsigned len)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    sqlite3_stmt *stmt;
    bool result = false;

    int rc = sqlite3_prepare(db, "INSERT OR REPLACE INTO statecache (id, content) VALUES (?, ?)", -1, &stmt, NULL);
    if (rc == SQLITE_OK)
    {
        rc = sqlite3_bind_int(stmt, 1, index);
        if (rc == SQLITE_OK)
        {
            rc = sqlite3_bind_blob(stmt, 2, data, len, SQLITE_STATIC);
            if (rc == SQLITE_OK)
            {

                rc = sqlite3_step(stmt);
                if (rc == SQLITE_DONE)
                {
                    result = true;
                }
            }
        }
    }

    sqlite3_finalize(stmt);

    if (!result)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to put record into database: " << dbfile << err;
        assert(!"Unable to put record into database.");
    }

    return result;
}

// delete record by index
bool SqliteDbTable::del(uint32_t index)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    char buf[64];

    sprintf(buf, "DELETE FROM statecache WHERE id = %" PRIu32, index);

    int rc = sqlite3_exec(db, buf, 0, 0, nullptr);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to delete record from database: " << dbfile << err;
        assert(!"Unable to delete record from database.");

        return false;
    }

    return true;
}

// truncate table
void SqliteDbTable::truncate()
{
    if (!db)
    {
        return;
    }

    checkTransaction();

    int rc = sqlite3_exec(db, "DELETE FROM statecache", 0, 0, NULL);
    if (rc != API_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to truncate database: " << dbfile << err;
        assert(!"Unable to truncate database.");
    }
}

// begin transaction
void SqliteDbTable::begin()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction BEGIN " << dbfile;
    int rc = sqlite3_exec(db, "BEGIN", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to begin transaction on database: " << dbfile << err;
        assert(!"Unable to begin transaction on database.");
    }
}

// commit transaction
void SqliteDbTable::commit()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction COMMIT " << dbfile;

    int rc = sqlite3_exec(db, "COMMIT", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to commit transaction on database: " << dbfile << err;
        assert(!"Unable to commit transaction on database.");
    }
}

// abort transaction
void SqliteDbTable::abort()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction ROLLBACK " << dbfile;

    int rc = sqlite3_exec(db, "ROLLBACK", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to rollback transaction on database: " << dbfile << err;
        assert(!"Unable to rollback transaction on database.");
    }
}

void SqliteDbTable::remove()
{
    if (!db)
    {
        return;
    }

    sqlite3_finalize(pStmt);

    if (inTransaction())
    {
        abort();
    }

    sqlite3_close(db);

    db = NULL;

    auto localpath = LocalPath::fromPath(dbfile, *fsaccess);
    fsaccess->unlinklocal(localpath);
}

} // namespace

#endif
<commit_msg>Remove unneeded changes to DB schema<commit_after>/**
 * @file sqlite.cpp
 * @brief SQLite DB access layer
 *
 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega.h"

#ifdef USE_SQLITE
namespace mega {

SqliteDbAccess::SqliteDbAccess(const LocalPath& rootPath)
  : mRootPath(rootPath)
{
}

SqliteDbAccess::~SqliteDbAccess()
{
}

LocalPath SqliteDbAccess::databasePath(const FileSystemAccess& fsAccess,
                                       const string& name,
                                       const int version) const
{
    ostringstream osstream;

    osstream << "megaclient_statecache"
             << version
             << "_"
             << name
             << ".db";

    LocalPath path = mRootPath;

    path.appendWithSeparator(
      LocalPath::fromPath(osstream.str(), fsAccess),
      false);

    return path;
}

SqliteDbTable* SqliteDbAccess::open(PrnGen &rng, FileSystemAccess& fsAccess, const string& name, const int flags)
{
    auto dbPath = databasePath(fsAccess, name, DB_VERSION);
    auto upgraded = true;

    {
        auto legacyPath = databasePath(fsAccess, name, LEGACY_DB_VERSION);
        auto fileAccess = fsAccess.newfileaccess();

        if (fileAccess->fopen(legacyPath))
        {
            LOG_debug << "Found legacy database at: " << legacyPath.toPath(fsAccess);

            if (currentDbVersion == LEGACY_DB_VERSION)
            {
                LOG_debug << "Using a legacy database.";
                dbPath = std::move(legacyPath);
                upgraded = false;
            }
            else if ((flags & DB_OPEN_FLAG_RECYCLE))
            {
                LOG_debug << "Trying to recycle a legacy database.";

                if (fsAccess.renamelocal(legacyPath, dbPath, false))
                {
                    auto suffix = LocalPath::fromPath("-shm", fsAccess);
                    auto from = legacyPath + suffix;
                    auto to = dbPath + suffix;

                    fsAccess.renamelocal(from, to);

                    suffix = LocalPath::fromPath("-wal", fsAccess);
                    from = legacyPath + suffix;
                    to = dbPath + suffix;

                    fsAccess.renamelocal(from, to);

                    LOG_debug << "Legacy database recycled.";
                }
                else
                {
                    LOG_debug << "Unable to recycle database, deleting...";
                    fsAccess.unlinklocal(legacyPath);
                }
            }
            else
            {
                LOG_debug << "Deleting outdated legacy database.";
                fsAccess.unlinklocal(legacyPath);
            }
        }
    }

    if (upgraded)
    {
        LOG_debug << "Using an upgraded DB: " << dbPath.toPath(fsAccess);
        currentDbVersion = DB_VERSION;
    }

    const string dbPathStr = dbPath.toPath(fsAccess);
    sqlite3* db;
    int result = sqlite3_open(dbPathStr.c_str(), &db);

    if (result)
    {
        if (db)
        {
            sqlite3_close(db);
        }

        return nullptr;
    }

#if !(TARGET_OS_IPHONE)
    result = sqlite3_exec(db, "PRAGMA journal_mode=WAL;", nullptr, nullptr, nullptr);
    if (result)
    {
        sqlite3_close(db);
        return nullptr;
    }
#endif /* ! TARGET_OS_IPHONE */

    const char* sql =
      "CREATE TABLE IF NOT EXISTS statecache ( "
      "    id INTEGER PRIMARY KEY ASC NOT NULL, "
      "    content BLOB NOT NULL "
      ");";

    result = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
    if (result)
    {
        sqlite3_close(db);
        return nullptr;
    }

    return new SqliteDbTable(rng,
                             db,
                             fsAccess,
                             dbPathStr,
                             (flags & DB_OPEN_FLAG_TRANSACTED) > 0);
}

bool SqliteDbAccess::probe(FileSystemAccess& fsAccess, const string& name) const
{
    auto fileAccess = fsAccess.newfileaccess();

    LocalPath dbPath = databasePath(fsAccess, name, DB_VERSION);

    if (fileAccess->isfile(dbPath))
    {
        return true;
    }

    dbPath = databasePath(fsAccess, name, LEGACY_DB_VERSION);

    return fileAccess->isfile(dbPath);
}

const LocalPath& SqliteDbAccess::rootPath() const
{
    return mRootPath;
}

SqliteDbTable::SqliteDbTable(PrnGen &rng, sqlite3* db, FileSystemAccess &fsAccess, const string &path, const bool checkAlwaysTransacted)
  : DbTable(rng, checkAlwaysTransacted)
  , db(db)
  , pStmt(nullptr)
  , dbfile(path)
  , fsaccess(&fsAccess)
{
}

SqliteDbTable::~SqliteDbTable()
{
    resetCommitter();

    if (!db)
    {
        return;
    }

    sqlite3_finalize(pStmt);

    if (inTransaction())
    {
        abort();
    }

    sqlite3_close(db);
    LOG_debug << "Database closed " << dbfile;
}

bool SqliteDbTable::inTransaction() const
{
    return sqlite3_get_autocommit(db) == 0;
}

LocalPath SqliteDbTable::dbFile() const
{
    return LocalPath::fromPath(dbfile, *fsaccess);
}

// set cursor to first record
void SqliteDbTable::rewind()
{
    if (!db)
    {
        return;
    }

    int result;

    if (pStmt)
    {
        result = sqlite3_reset(pStmt);
    }
    else
    {
        result = sqlite3_prepare(db, "SELECT id, content FROM statecache", -1, &pStmt, NULL);
    }

    if (result != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(result));
        LOG_err << "Unable to rewind database: " << dbfile << err;
        assert(!"Unable to rewind database.");
    }
}

// retrieve next record through cursor
bool SqliteDbTable::next(uint32_t* index, string* data)
{
    if (!db)
    {
        return false;
    }

    if (!pStmt)
    {
        return false;
    }

    int rc = sqlite3_step(pStmt);

    if (rc != SQLITE_ROW)
    {
        sqlite3_finalize(pStmt);
        pStmt = NULL;

        if (rc != SQLITE_DONE)
        {
            string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
            LOG_err << "Unable to get next record from database: " << dbfile << err;
            assert(!"Unable to get next record from database.");
        }

        return false;
    }

    *index = sqlite3_column_int(pStmt, 0);

    data->assign((char*)sqlite3_column_blob(pStmt, 1), sqlite3_column_bytes(pStmt, 1));

    return true;
}

// retrieve record by index
bool SqliteDbTable::get(uint32_t index, string* data)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    sqlite3_stmt *stmt;
    int rc;

    rc = sqlite3_prepare(db, "SELECT content FROM statecache WHERE id = ?", -1, &stmt, NULL);
    if (rc == SQLITE_OK)
    {
        rc = sqlite3_bind_int(stmt, 1, index);
        if (rc == SQLITE_OK)
        {
            rc = sqlite3_step(stmt);
            if (rc == SQLITE_ROW)
            {
                data->assign((char*)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
            }
        }
    }

    sqlite3_finalize(stmt);

    if (rc != SQLITE_DONE && rc != SQLITE_ROW)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to get record from database: " << dbfile << err;
        assert(!"Unable to get record from database.");
    }

    return rc == SQLITE_ROW;
}

// add/update record by index
bool SqliteDbTable::put(uint32_t index, char* data, unsigned len)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    sqlite3_stmt *stmt;
    bool result = false;

    int rc = sqlite3_prepare(db, "INSERT OR REPLACE INTO statecache (id, content) VALUES (?, ?)", -1, &stmt, NULL);
    if (rc == SQLITE_OK)
    {
        rc = sqlite3_bind_int(stmt, 1, index);
        if (rc == SQLITE_OK)
        {
            rc = sqlite3_bind_blob(stmt, 2, data, len, SQLITE_STATIC);
            if (rc == SQLITE_OK)
            {

                rc = sqlite3_step(stmt);
                if (rc == SQLITE_DONE)
                {
                    result = true;
                }
            }
        }
    }

    sqlite3_finalize(stmt);

    if (!result)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to put record into database: " << dbfile << err;
        assert(!"Unable to put record into database.");
    }

    return result;
}

// delete record by index
bool SqliteDbTable::del(uint32_t index)
{
    if (!db)
    {
        return false;
    }

    checkTransaction();

    char buf[64];

    sprintf(buf, "DELETE FROM statecache WHERE id = %" PRIu32, index);

    int rc = sqlite3_exec(db, buf, 0, 0, nullptr);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to delete record from database: " << dbfile << err;
        assert(!"Unable to delete record from database.");

        return false;
    }

    return true;
}

// truncate table
void SqliteDbTable::truncate()
{
    if (!db)
    {
        return;
    }

    checkTransaction();

    int rc = sqlite3_exec(db, "DELETE FROM statecache", 0, 0, NULL);
    if (rc != API_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to truncate database: " << dbfile << err;
        assert(!"Unable to truncate database.");
    }
}

// begin transaction
void SqliteDbTable::begin()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction BEGIN " << dbfile;
    int rc = sqlite3_exec(db, "BEGIN", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to begin transaction on database: " << dbfile << err;
        assert(!"Unable to begin transaction on database.");
    }
}

// commit transaction
void SqliteDbTable::commit()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction COMMIT " << dbfile;

    int rc = sqlite3_exec(db, "COMMIT", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to commit transaction on database: " << dbfile << err;
        assert(!"Unable to commit transaction on database.");
    }
}

// abort transaction
void SqliteDbTable::abort()
{
    if (!db)
    {
        return;
    }

    LOG_debug << "DB transaction ROLLBACK " << dbfile;

    int rc = sqlite3_exec(db, "ROLLBACK", 0, 0, NULL);
    if (rc != SQLITE_OK)
    {
        string err = string(" Error: ") + (sqlite3_errmsg(db) ? sqlite3_errmsg(db) : std::to_string(rc));
        LOG_err << "Unable to rollback transaction on database: " << dbfile << err;
        assert(!"Unable to rollback transaction on database.");
    }
}

void SqliteDbTable::remove()
{
    if (!db)
    {
        return;
    }

    sqlite3_finalize(pStmt);

    if (inTransaction())
    {
        abort();
    }

    sqlite3_close(db);

    db = NULL;

    auto localpath = LocalPath::fromPath(dbfile, *fsaccess);
    fsaccess->unlinklocal(localpath);
}

} // namespace
#endif
<|endoftext|>


<commit_before>#include "game.h"

// My strategy to play the dice sum game
// Returns 0 for ten's position, 1 for one's position
int myStrategy(int gameState[4][2], int diceValue) {
	static int initialized;		// Static variable, default to zero
	// Add your declaration of DP structure here
	if (!initialized) {
		initialized = 1;
		// Populate your structure here
	}
	int tenAvailCount = 0;	// No. of available ten's position
	for (int j = 0; j < 4; j++)
		if (gameState[j][0] <= 0) {tenAvailCount = 4 - j; break;}
	int oneAvailCount = 0;	// No. of available one's position
	for (int j = 0; j < 4; j++)
		if (gameState[j][1] <= 0) {oneAvailCount = 4 - j; break;}
	if ((tenAvailCount != 0) && (oneAvailCount == 0)) return (0);
	if ((tenAvailCount == 0) && (oneAvailCount != 0)) return (1);
//	My strategy
	int strategy = 1;
	int nextPos, total;
	switch (strategy) {
	case 1:
		nextPos = rand() % 2;
		break;
	case 2:
		nextPos = 0;
		total = (gameState[0][0] + gameState[1][0] + gameState[2][0] + gameState[3][0]) * 10
		        + (gameState[0][1] + gameState[1][1] + gameState[2][1] + gameState[3][1]);
		if (total + diceValue * 10 > SCOREMAX)
			nextPos = 1;
		break;
	case 3:
		// Add your own strategy (which uses the DP structure) here
		break;
	default:
		printf("Error!\n");
	}
	return (nextPos);
}
<commit_msg>add accepted HW5<commit_after>#include "game.h"
#define POSITION_TEN 0
#define POSITION_ONE 1

static int dp[5][5][152];
static int score;
static const int penalty = -100;

static int expScore(int tens, int ones, int score) {
	if (score > SCOREMAX)
		return penalty;

	if (dp[tens][ones][score])
		return dp[tens][ones][score];

	if (tens == 0 && ones == 0) {
		return dp[0][0][score] = score <= SCOREMAX ? score : penalty;
	}

	int expval = 0;
	for (int i = 1; i <= 6; i++) {
		expval += max(tens > 0 ? expScore(tens - 1, ones, score + i * 10) : 0,
		              ones > 0 ? expScore(tens, ones - 1, score + i)      : 0);
	}

	return dp[tens][ones][score] = expval;
}

static int getAvailCount(int state[][2], int offs) {
	for (int i = 0; i < 4; i++)
		if (state[i][offs] > 0) {
			score += state[i][offs] * (offs == POSITION_TEN ? 10 : 1);
		} else return 4 - i;
	return 0;
}

__attribute__((constructor))
static void initializeTable() {
	expScore(4, 4, 0);
}

// My strategy to play the dice sum game
// Returns 0 for ten's position, 1 for one's position
int myStrategy(int gameState[4][2], int diceValue) {
	score = 0;
	int tenAvailCount = getAvailCount(gameState, POSITION_TEN);
	int oneAvailCount = getAvailCount(gameState, POSITION_ONE);
	// score is calculated now (bad coding style, I know)

	if (oneAvailCount == 0) return POSITION_TEN;
	if (tenAvailCount == 0) return POSITION_ONE;

	return (expScore(tenAvailCount - 1, oneAvailCount, score + diceValue * 10) >
	        expScore(tenAvailCount, oneAvailCount - 1, score + diceValue)) ?
	       POSITION_TEN : POSITION_ONE;
}
<|endoftext|>


<commit_before>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <vector>

namespace meshopt
{

static unsigned int MurmurHash2(const void* key, size_t len, unsigned int seed)
{
	const unsigned int m = 0x5bd1e995;
	const int r = 24;

	unsigned int h = seed ^ static_cast<unsigned int>(len);

	// Mix 4 bytes at a time into the hash
	const unsigned char* data = (const unsigned char*)key;

	while (len >= 4)
	{
		unsigned int k = *(unsigned int*)data;

		k *= m;
		k ^= k >> r;
		k *= m;

		h *= m;
		h ^= k;

		data += 4;
		len -= 4;
	}

	// Handle the last few bytes of the input array
	switch (len)
	{
	case 3:
		h ^= data[2] << 16;
	case 2:
		h ^= data[1] << 8;
	case 1:
		h ^= data[0];
		h *= m;
	};

	// Do a few final mixes of the hash to ensure the last few
	// bytes are well-incorporated.

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
}

struct VertexHasher
{
	const char* vertices;
	size_t vertex_size;

	unsigned int empty() const
	{
		return ~0u;
	}

	size_t operator()(unsigned int index) const
	{
		return MurmurHash2(vertices + index * vertex_size, vertex_size, 0);
	}

	size_t operator()(unsigned int lhs, unsigned int rhs) const
	{
		return memcmp(vertices + lhs * vertex_size, vertices + rhs * vertex_size, vertex_size) == 0;
	}
};

struct VertexHashEntry
{
	unsigned int key;
	unsigned int value;
};

template <typename T, typename Hash>
static void hashInit(std::vector<T>& table, const Hash& hash, size_t count)
{
	size_t buckets = 1;
	while (buckets < count)
		buckets *= 2;

	T dummy = T();
	dummy.key = hash.empty();

	table.clear();
	table.resize(buckets, dummy);
}

template <typename T, typename Hash, typename Key>
static T* hashLookup(std::vector<T>& table, const Hash& hash, const Key& key)
{
	assert((table.size() & (table.size() - 1)) == 0);

	size_t hashmod = table.size() - 1;
	size_t hashval = hash(key);
	size_t bucket = hashval & hashmod;

	for (size_t probe = 0; probe <= hashmod; ++probe)
	{
		T& item = table[bucket];

		if (item.key == hash.empty())
			return &item;

		if (hash(item.key, key))
			return &item;

		// hash collision, quadratic probing
		bucket = (bucket + probe + 1) & hashmod;
	}

	assert(false && "Hash table is full");
	return 0;
}

} // namespace meshopt

size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
{
	using namespace meshopt;

	assert(indices || index_count == vertex_count);
	assert(index_count % 3 == 0);
	assert(vertex_size > 0);

	for (size_t i = 0; i < vertex_count; ++i)
	{
		destination[i] = ~0u;
	}

	VertexHasher hasher = {static_cast<const char*>(vertices), vertex_size};

	std::vector<VertexHashEntry> table;
	hashInit(table, hasher, vertex_count);

	unsigned int next_vertex = 0;

	for (size_t i = 0; i < index_count; ++i)
	{
		unsigned int index = indices ? indices[i] : unsigned(i);
		assert(index < vertex_count);

		if (destination[index] == ~0u)
		{
			VertexHashEntry* entry = hashLookup(table, hasher, index);

			if (entry->key == ~0u)
			{
				entry->key = index;
				entry->value = next_vertex++;
			}

			destination[index] = entry->value;
		}
	}

	return next_vertex;
}

void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
{
	assert(destination != vertices);
	assert(vertex_size > 0);

	for (size_t i = 0; i < vertex_count; ++i)
	{
		memcpy(static_cast<char*>(destination) + remap[i] * vertex_size, static_cast<const char*>(vertices) + i * vertex_size, vertex_size);
	}
}

void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
{
	assert(index_count % 3 == 0);

	if (indices)
	{
		for (size_t i = 0; i < index_count; ++i)
		{
			destination[i] = remap[indices[i]];
		}
	}
	else
	{
		for (size_t i = 0; i < index_count; ++i)
		{
			destination[i] = remap[i];
		}
	}
}
<commit_msg>indexgenerator: Fix VB remap when some vertices are unused<commit_after>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <vector>

namespace meshopt
{

static unsigned int murmurHash2(const void* key, size_t len, unsigned int seed)
{
	const unsigned int m = 0x5bd1e995;
	const int r = 24;

	unsigned int h = seed ^ static_cast<unsigned int>(len);

	// Mix 4 bytes at a time into the hash
	const unsigned char* data = (const unsigned char*)key;

	while (len >= 4)
	{
		unsigned int k = *(unsigned int*)data;

		k *= m;
		k ^= k >> r;
		k *= m;

		h *= m;
		h ^= k;

		data += 4;
		len -= 4;
	}

	// Handle the last few bytes of the input array
	switch (len)
	{
	case 3:
		h ^= data[2] << 16;
	case 2:
		h ^= data[1] << 8;
	case 1:
		h ^= data[0];
		h *= m;
	};

	// Do a few final mixes of the hash to ensure the last few
	// bytes are well-incorporated.

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
}

struct VertexHasher
{
	const char* vertices;
	size_t vertex_size;

	unsigned int empty() const
	{
		return ~0u;
	}

	size_t operator()(unsigned int index) const
	{
		return murmurHash2(vertices + index * vertex_size, vertex_size, 0);
	}

	size_t operator()(unsigned int lhs, unsigned int rhs) const
	{
		return memcmp(vertices + lhs * vertex_size, vertices + rhs * vertex_size, vertex_size) == 0;
	}
};

struct VertexHashEntry
{
	unsigned int key;
	unsigned int value;
};

template <typename T, typename Hash>
static void hashInit(std::vector<T>& table, const Hash& hash, size_t count)
{
	size_t buckets = 1;
	while (buckets < count)
		buckets *= 2;

	T dummy = T();
	dummy.key = hash.empty();

	table.clear();
	table.resize(buckets, dummy);
}

template <typename T, typename Hash, typename Key>
static T* hashLookup(std::vector<T>& table, const Hash& hash, const Key& key)
{
	assert((table.size() & (table.size() - 1)) == 0);

	size_t hashmod = table.size() - 1;
	size_t hashval = hash(key);
	size_t bucket = hashval & hashmod;

	for (size_t probe = 0; probe <= hashmod; ++probe)
	{
		T& item = table[bucket];

		if (item.key == hash.empty())
			return &item;

		if (hash(item.key, key))
			return &item;

		// hash collision, quadratic probing
		bucket = (bucket + probe + 1) & hashmod;
	}

	assert(false && "Hash table is full");
	return 0;
}

} // namespace meshopt

size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
{
	using namespace meshopt;

	assert(indices || index_count == vertex_count);
	assert(index_count % 3 == 0);
	assert(vertex_size > 0);

	for (size_t i = 0; i < vertex_count; ++i)
	{
		destination[i] = ~0u;
	}

	VertexHasher hasher = {static_cast<const char*>(vertices), vertex_size};

	std::vector<VertexHashEntry> table;
	hashInit(table, hasher, vertex_count);

	unsigned int next_vertex = 0;

	for (size_t i = 0; i < index_count; ++i)
	{
		unsigned int index = indices ? indices[i] : unsigned(i);
		assert(index < vertex_count);

		if (destination[index] == ~0u)
		{
			VertexHashEntry* entry = hashLookup(table, hasher, index);

			if (entry->key == ~0u)
			{
				entry->key = index;
				entry->value = next_vertex++;
			}

			destination[index] = entry->value;
		}
	}

	return next_vertex;
}

void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
{
	assert(destination != vertices);
	assert(vertex_size > 0);

	for (size_t i = 0; i < vertex_count; ++i)
	{
		if (remap[i] != ~0u)
		{
			memcpy(static_cast<char*>(destination) + remap[i] * vertex_size, static_cast<const char*>(vertices) + i * vertex_size, vertex_size);
		}
	}
}

void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
{
	assert(index_count % 3 == 0);

	for (size_t i = 0; i < index_count; ++i)
	{
		unsigned int index = indices ? indices[i] : unsigned(i);
		assert(remap[index] != ~0u);

		destination[i] = remap[index];
	}
}
<|endoftext|>