<commit_before>/*
 * Copyright © 2013 Intel 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 (including the next
 * paragraph) 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 builtin_types.cpp
 *
 * The glsl_type class has static members to represent all the built-in types
 * (such as the glsl_type::_float_type flyweight) as well as convenience pointer
 * accessors (such as glsl_type::float_type).  Those global variables are
 * declared and initialized in this file.
 *
 * This also contains _mesa_glsl_initialize_types(), a function which populates
 * a symbol table with the available built-in types for a particular language
 * version and set of enabled extensions.
 */

#include "glsl_types.h"
#include "glsl_parser_extras.h"

/**
 * Declarations of type flyweights (glsl_type::_foo_type) and
 * convenience pointers (glsl_type::foo_type).
 * @{
 */
#define DECL_TYPE(NAME, ...)                                    \
   const glsl_type glsl_type::_##NAME##_type = glsl_type(__VA_ARGS__, #NAME); \
   const glsl_type *const glsl_type::NAME##_type = &glsl_type::_##NAME##_type;

#define STRUCT_TYPE(NAME)                                       \
   const glsl_type glsl_type::_struct_##NAME##_type =           \
      glsl_type(NAME##_fields, Elements(NAME##_fields), #NAME); \
   const glsl_type *const glsl_type::struct_##NAME##_type =     \
      &glsl_type::_struct_##NAME##_type;

static const struct glsl_struct_field gl_DepthRangeParameters_fields[] = {
   { glsl_type::float_type, "near", false },
   { glsl_type::float_type, "far",  false },
   { glsl_type::float_type, "diff", false },
};

static const struct glsl_struct_field gl_PointParameters_fields[] = {
   { glsl_type::float_type, "size", false },
   { glsl_type::float_type, "sizeMin", false },
   { glsl_type::float_type, "sizeMax", false },
   { glsl_type::float_type, "fadeThresholdSize", false },
   { glsl_type::float_type, "distanceConstantAttenuation", false },
   { glsl_type::float_type, "distanceLinearAttenuation", false },
   { glsl_type::float_type, "distanceQuadraticAttenuation", false },
};

static const struct glsl_struct_field gl_MaterialParameters_fields[] = {
   { glsl_type::vec4_type, "emission", false },
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
   { glsl_type::float_type, "shininess", false },
};

static const struct glsl_struct_field gl_LightSourceParameters_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
   { glsl_type::vec4_type, "position", false },
   { glsl_type::vec4_type, "halfVector", false },
   { glsl_type::vec3_type, "spotDirection", false },
   { glsl_type::float_type, "spotExponent", false },
   { glsl_type::float_type, "spotCutoff", false },
   { glsl_type::float_type, "spotCosCutoff", false },
   { glsl_type::float_type, "constantAttenuation", false },
   { glsl_type::float_type, "linearAttenuation", false },
   { glsl_type::float_type, "quadraticAttenuation", false },
};

static const struct glsl_struct_field gl_LightModelParameters_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
};

static const struct glsl_struct_field gl_LightModelProducts_fields[] = {
   { glsl_type::vec4_type, "sceneColor", false },
};

static const struct glsl_struct_field gl_LightProducts_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
};

static const struct glsl_struct_field gl_FogParameters_fields[] = {
   { glsl_type::vec4_type, "color", false },
   { glsl_type::float_type, "density", false },
   { glsl_type::float_type, "start", false },
   { glsl_type::float_type, "end", false },
   { glsl_type::float_type, "scale", false },
};

#include "builtin_type_macros.h"
/** @} */

/**
 * Code to populate a symbol table with the built-in types available in a
 * particular shading language version.  The table below contains tags every
 * type with the GLSL/GLSL ES versions where it was introduced.
 *
 * @{
 */
#define T(TYPE, MIN_GL, MIN_ES) \
   { glsl_type::TYPE##_type, MIN_GL, MIN_ES },

const static struct builtin_type_versions {
   const glsl_type *const type;
   int min_gl;
   int min_es;
} builtin_type_versions[] = {
   T(void,                            110, 100)
   T(bool,                            110, 100)
   T(bvec2,                           110, 100)
   T(bvec3,                           110, 100)
   T(bvec4,                           110, 100)
   T(int,                             110, 100)
   T(ivec2,                           110, 100)
   T(ivec3,                           110, 100)
   T(ivec4,                           110, 100)
   T(uint,                            130, 300)
   T(uvec2,                           130, 300)
   T(uvec3,                           130, 300)
   T(uvec4,                           130, 300)
   T(float,                           110, 100)
   T(vec2,                            110, 100)
   T(vec3,                            110, 100)
   T(vec4,                            110, 100)
   T(mat2,                            110, 100)
   T(mat3,                            110, 100)
   T(mat4,                            110, 100)
   T(mat2x3,                          120, 300)
   T(mat2x4,                          120, 300)
   T(mat3x2,                          120, 300)
   T(mat3x4,                          120, 300)
   T(mat4x2,                          120, 300)
   T(mat4x3,                          120, 300)

   T(sampler1D,                       110, 999)
   T(sampler2D,                       110, 100)
   T(sampler3D,                       110, 300)
   T(samplerCube,                     110, 100)
   T(sampler1DArray,                  130, 999)
   T(sampler2DArray,                  130, 300)
   T(samplerCubeArray,                400, 999)
   T(sampler2DRect,                   140, 999)
   T(samplerBuffer,                   140, 999)
   T(sampler2DMS,                     150, 999)
   T(sampler2DMSArray,                150, 999)

   T(isampler1D,                      130, 999)
   T(isampler2D,                      130, 300)
   T(isampler3D,                      130, 300)
   T(isamplerCube,                    130, 300)
   T(isampler1DArray,                 130, 999)
   T(isampler2DArray,                 130, 300)
   T(isamplerCubeArray,               400, 999)
   T(isampler2DRect,                  140, 999)
   T(isamplerBuffer,                  140, 999)
   T(isampler2DMS,                    150, 999)
   T(isampler2DMSArray,               150, 999)

   T(usampler1D,                      130, 999)
   T(usampler2D,                      130, 300)
   T(usampler3D,                      130, 300)
   T(usamplerCube,                    130, 300)
   T(usampler1DArray,                 130, 999)
   T(usampler2DArray,                 130, 300)
   T(usamplerCubeArray,               400, 999)
   T(usampler2DRect,                  140, 999)
   T(usamplerBuffer,                  140, 999)
   T(usampler2DMS,                    150, 999)
   T(usampler2DMSArray,               150, 999)

   T(sampler1DShadow,                 110, 999)
   T(sampler2DShadow,                 110, 300)
   T(samplerCubeShadow,               130, 300)
   T(sampler1DArrayShadow,            130, 999)
   T(sampler2DArrayShadow,            130, 300)
   T(samplerCubeArrayShadow,          400, 999)
   T(sampler2DRectShadow,             140, 999)

   T(struct_gl_DepthRangeParameters,  110, 100)
};

const glsl_type *const deprecated_types[] = {
   glsl_type::struct_gl_PointParameters_type,
   glsl_type::struct_gl_MaterialParameters_type,
   glsl_type::struct_gl_LightSourceParameters_type,
   glsl_type::struct_gl_LightModelParameters_type,
   glsl_type::struct_gl_LightModelProducts_type,
   glsl_type::struct_gl_LightProducts_type,
   glsl_type::struct_gl_FogParameters_type,
};

static inline void
add_type(glsl_symbol_table *symbols, const glsl_type *const type)
{
   symbols->add_type(type->name, type);
}

/**
 * Populate the symbol table with available built-in types.
 */
void
_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
{
   struct glsl_symbol_table *symbols = state->symbols;

   for (unsigned i = 0; i < Elements(builtin_type_versions); i++) {
      const struct builtin_type_versions *const t = &builtin_type_versions[i];
      if (state->is_version(t->min_gl, t->min_es)) {
         add_type(symbols, t->type);
      }
   }

   /* Add deprecated structure types.  While these were deprecated in 1.30,
    * they're still present.  We've removed them in 1.40+ (OpenGL 3.1+).
    */
   if (!state->es_shader && state->language_version < 140) {
      for (unsigned i = 0; i < Elements(deprecated_types); i++) {
         add_type(symbols, deprecated_types[i]);
      }
   }

   /* Add types for enabled extensions.  They may have already been added
    * by the version-based loop, but attempting to add them a second time
    * is harmless.
    */
   if (state->ARB_texture_cube_map_array_enable) {
      add_type(symbols, glsl_type::samplerCubeArray_type);
      add_type(symbols, glsl_type::samplerCubeArrayShadow_type);
      add_type(symbols, glsl_type::isamplerCubeArray_type);
      add_type(symbols, glsl_type::usamplerCubeArray_type);
   }

   if (state->ARB_texture_multisample_enable) {
      add_type(symbols, glsl_type::sampler2DMS_type);
      add_type(symbols, glsl_type::isampler2DMS_type);
      add_type(symbols, glsl_type::usampler2DMS_type);
      add_type(symbols, glsl_type::sampler2DMSArray_type);
      add_type(symbols, glsl_type::isampler2DMSArray_type);
      add_type(symbols, glsl_type::usampler2DMSArray_type);
   }

   if (state->ARB_texture_rectangle_enable) {
      add_type(symbols, glsl_type::sampler2DRect_type);
      add_type(symbols, glsl_type::sampler2DRectShadow_type);
   }

   if (state->EXT_texture_array_enable) {
      add_type(symbols, glsl_type::sampler1DArray_type);
      add_type(symbols, glsl_type::sampler2DArray_type);
      add_type(symbols, glsl_type::sampler1DArrayShadow_type);
      add_type(symbols, glsl_type::sampler2DArrayShadow_type);
   }

   if (state->OES_EGL_image_external_enable) {
      add_type(symbols, glsl_type::samplerExternalOES_type);
   }

   if (state->OES_texture_3D_enable) {
      add_type(symbols, glsl_type::sampler3D_type);
   }
}
/** @} */
<commit_msg>re-add EXT_shadow_samplers type lost in the merge<commit_after>/*
 * Copyright © 2013 Intel 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 (including the next
 * paragraph) 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 builtin_types.cpp
 *
 * The glsl_type class has static members to represent all the built-in types
 * (such as the glsl_type::_float_type flyweight) as well as convenience pointer
 * accessors (such as glsl_type::float_type).  Those global variables are
 * declared and initialized in this file.
 *
 * This also contains _mesa_glsl_initialize_types(), a function which populates
 * a symbol table with the available built-in types for a particular language
 * version and set of enabled extensions.
 */

#include "glsl_types.h"
#include "glsl_parser_extras.h"

/**
 * Declarations of type flyweights (glsl_type::_foo_type) and
 * convenience pointers (glsl_type::foo_type).
 * @{
 */
#define DECL_TYPE(NAME, ...)                                    \
   const glsl_type glsl_type::_##NAME##_type = glsl_type(__VA_ARGS__, #NAME); \
   const glsl_type *const glsl_type::NAME##_type = &glsl_type::_##NAME##_type;

#define STRUCT_TYPE(NAME)                                       \
   const glsl_type glsl_type::_struct_##NAME##_type =           \
      glsl_type(NAME##_fields, Elements(NAME##_fields), #NAME); \
   const glsl_type *const glsl_type::struct_##NAME##_type =     \
      &glsl_type::_struct_##NAME##_type;

static const struct glsl_struct_field gl_DepthRangeParameters_fields[] = {
   { glsl_type::float_type, "near", false },
   { glsl_type::float_type, "far",  false },
   { glsl_type::float_type, "diff", false },
};

static const struct glsl_struct_field gl_PointParameters_fields[] = {
   { glsl_type::float_type, "size", false },
   { glsl_type::float_type, "sizeMin", false },
   { glsl_type::float_type, "sizeMax", false },
   { glsl_type::float_type, "fadeThresholdSize", false },
   { glsl_type::float_type, "distanceConstantAttenuation", false },
   { glsl_type::float_type, "distanceLinearAttenuation", false },
   { glsl_type::float_type, "distanceQuadraticAttenuation", false },
};

static const struct glsl_struct_field gl_MaterialParameters_fields[] = {
   { glsl_type::vec4_type, "emission", false },
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
   { glsl_type::float_type, "shininess", false },
};

static const struct glsl_struct_field gl_LightSourceParameters_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
   { glsl_type::vec4_type, "position", false },
   { glsl_type::vec4_type, "halfVector", false },
   { glsl_type::vec3_type, "spotDirection", false },
   { glsl_type::float_type, "spotExponent", false },
   { glsl_type::float_type, "spotCutoff", false },
   { glsl_type::float_type, "spotCosCutoff", false },
   { glsl_type::float_type, "constantAttenuation", false },
   { glsl_type::float_type, "linearAttenuation", false },
   { glsl_type::float_type, "quadraticAttenuation", false },
};

static const struct glsl_struct_field gl_LightModelParameters_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
};

static const struct glsl_struct_field gl_LightModelProducts_fields[] = {
   { glsl_type::vec4_type, "sceneColor", false },
};

static const struct glsl_struct_field gl_LightProducts_fields[] = {
   { glsl_type::vec4_type, "ambient", false },
   { glsl_type::vec4_type, "diffuse", false },
   { glsl_type::vec4_type, "specular", false },
};

static const struct glsl_struct_field gl_FogParameters_fields[] = {
   { glsl_type::vec4_type, "color", false },
   { glsl_type::float_type, "density", false },
   { glsl_type::float_type, "start", false },
   { glsl_type::float_type, "end", false },
   { glsl_type::float_type, "scale", false },
};

#include "builtin_type_macros.h"
/** @} */

/**
 * Code to populate a symbol table with the built-in types available in a
 * particular shading language version.  The table below contains tags every
 * type with the GLSL/GLSL ES versions where it was introduced.
 *
 * @{
 */
#define T(TYPE, MIN_GL, MIN_ES) \
   { glsl_type::TYPE##_type, MIN_GL, MIN_ES },

const static struct builtin_type_versions {
   const glsl_type *const type;
   int min_gl;
   int min_es;
} builtin_type_versions[] = {
   T(void,                            110, 100)
   T(bool,                            110, 100)
   T(bvec2,                           110, 100)
   T(bvec3,                           110, 100)
   T(bvec4,                           110, 100)
   T(int,                             110, 100)
   T(ivec2,                           110, 100)
   T(ivec3,                           110, 100)
   T(ivec4,                           110, 100)
   T(uint,                            130, 300)
   T(uvec2,                           130, 300)
   T(uvec3,                           130, 300)
   T(uvec4,                           130, 300)
   T(float,                           110, 100)
   T(vec2,                            110, 100)
   T(vec3,                            110, 100)
   T(vec4,                            110, 100)
   T(mat2,                            110, 100)
   T(mat3,                            110, 100)
   T(mat4,                            110, 100)
   T(mat2x3,                          120, 300)
   T(mat2x4,                          120, 300)
   T(mat3x2,                          120, 300)
   T(mat3x4,                          120, 300)
   T(mat4x2,                          120, 300)
   T(mat4x3,                          120, 300)

   T(sampler1D,                       110, 999)
   T(sampler2D,                       110, 100)
   T(sampler3D,                       110, 300)
   T(samplerCube,                     110, 100)
   T(sampler1DArray,                  130, 999)
   T(sampler2DArray,                  130, 300)
   T(samplerCubeArray,                400, 999)
   T(sampler2DRect,                   140, 999)
   T(samplerBuffer,                   140, 999)
   T(sampler2DMS,                     150, 999)
   T(sampler2DMSArray,                150, 999)

   T(isampler1D,                      130, 999)
   T(isampler2D,                      130, 300)
   T(isampler3D,                      130, 300)
   T(isamplerCube,                    130, 300)
   T(isampler1DArray,                 130, 999)
   T(isampler2DArray,                 130, 300)
   T(isamplerCubeArray,               400, 999)
   T(isampler2DRect,                  140, 999)
   T(isamplerBuffer,                  140, 999)
   T(isampler2DMS,                    150, 999)
   T(isampler2DMSArray,               150, 999)

   T(usampler1D,                      130, 999)
   T(usampler2D,                      130, 300)
   T(usampler3D,                      130, 300)
   T(usamplerCube,                    130, 300)
   T(usampler1DArray,                 130, 999)
   T(usampler2DArray,                 130, 300)
   T(usamplerCubeArray,               400, 999)
   T(usampler2DRect,                  140, 999)
   T(usamplerBuffer,                  140, 999)
   T(usampler2DMS,                    150, 999)
   T(usampler2DMSArray,               150, 999)

   T(sampler1DShadow,                 110, 999)
   T(sampler2DShadow,                 110, 300)
   T(samplerCubeShadow,               130, 300)
   T(sampler1DArrayShadow,            130, 999)
   T(sampler2DArrayShadow,            130, 300)
   T(samplerCubeArrayShadow,          400, 999)
   T(sampler2DRectShadow,             140, 999)

   T(struct_gl_DepthRangeParameters,  110, 100)
};

const glsl_type *const deprecated_types[] = {
   glsl_type::struct_gl_PointParameters_type,
   glsl_type::struct_gl_MaterialParameters_type,
   glsl_type::struct_gl_LightSourceParameters_type,
   glsl_type::struct_gl_LightModelParameters_type,
   glsl_type::struct_gl_LightModelProducts_type,
   glsl_type::struct_gl_LightProducts_type,
   glsl_type::struct_gl_FogParameters_type,
};

static inline void
add_type(glsl_symbol_table *symbols, const glsl_type *const type)
{
   symbols->add_type(type->name, type);
}

/**
 * Populate the symbol table with available built-in types.
 */
void
_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
{
   struct glsl_symbol_table *symbols = state->symbols;

   for (unsigned i = 0; i < Elements(builtin_type_versions); i++) {
      const struct builtin_type_versions *const t = &builtin_type_versions[i];
      if (state->is_version(t->min_gl, t->min_es)) {
         add_type(symbols, t->type);
      }
   }

   /* Add deprecated structure types.  While these were deprecated in 1.30,
    * they're still present.  We've removed them in 1.40+ (OpenGL 3.1+).
    */
   if (!state->es_shader && state->language_version < 140) {
      for (unsigned i = 0; i < Elements(deprecated_types); i++) {
         add_type(symbols, deprecated_types[i]);
      }
   }

   /* Add types for enabled extensions.  They may have already been added
    * by the version-based loop, but attempting to add them a second time
    * is harmless.
    */
   if (state->ARB_texture_cube_map_array_enable) {
      add_type(symbols, glsl_type::samplerCubeArray_type);
      add_type(symbols, glsl_type::samplerCubeArrayShadow_type);
      add_type(symbols, glsl_type::isamplerCubeArray_type);
      add_type(symbols, glsl_type::usamplerCubeArray_type);
   }

   if (state->ARB_texture_multisample_enable) {
      add_type(symbols, glsl_type::sampler2DMS_type);
      add_type(symbols, glsl_type::isampler2DMS_type);
      add_type(symbols, glsl_type::usampler2DMS_type);
      add_type(symbols, glsl_type::sampler2DMSArray_type);
      add_type(symbols, glsl_type::isampler2DMSArray_type);
      add_type(symbols, glsl_type::usampler2DMSArray_type);
   }

   if (state->ARB_texture_rectangle_enable) {
      add_type(symbols, glsl_type::sampler2DRect_type);
      add_type(symbols, glsl_type::sampler2DRectShadow_type);
   }

   if (state->EXT_texture_array_enable) {
      add_type(symbols, glsl_type::sampler1DArray_type);
      add_type(symbols, glsl_type::sampler2DArray_type);
      add_type(symbols, glsl_type::sampler1DArrayShadow_type);
      add_type(symbols, glsl_type::sampler2DArrayShadow_type);
   }

   if (state->OES_EGL_image_external_enable) {
      add_type(symbols, glsl_type::samplerExternalOES_type);
   }

   if (state->EXT_shadow_samplers_enable) {
      add_type(symbols, glsl_type::sampler2DShadow_type);
   }

   if (state->OES_texture_3D_enable) {
      add_type(symbols, glsl_type::sampler3D_type);
   }
}
/** @} */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef STORED_VALUE_H
#define STORED_VALUE_H 1

#include "locks.hh"

extern "C" {
    extern rel_time_t (*ep_current_time)();
}

// Forward declaration for StoredValue
class HashTable;

class StoredValue {
public:
    StoredValue(const Item &itm, StoredValue *n) :
        key(itm.getKey()), value(const_cast<Item&>(itm).getData(), itm.getNBytes()),
        flags(itm.getFlags()), exptime(itm.getExptime()), dirtied(0), next(n),
        cas(itm.getCas())
    {
        markDirty();
    }

    StoredValue(const Item &itm, StoredValue *n, bool setDirty) :
        key(itm.getKey()), value(const_cast<Item&>(itm).getData(), itm.getNBytes()),
        flags(itm.getFlags()), exptime(itm.getExptime()), dirtied(0), next(n),
        cas(itm.getCas())
    {
        if (setDirty) {
            markDirty();
        } else {
            markClean(NULL, NULL);
        }
    }

    ~StoredValue() {
    }
    void markDirty() {
        data_age = ep_current_time();
        if (!isDirty()) {
            dirtied = data_age;
        }
    }

    void reDirty(rel_time_t dirtyAge, rel_time_t dataAge) {
        data_age = dataAge;
        dirtied = dirtyAge;
    }

    // returns time this object was dirtied.
    void markClean(rel_time_t *dirtyAge, rel_time_t *dataAge) {
        if (dirtyAge) {
            *dirtyAge = dirtied;
        }
        if (dataAge) {
            *dataAge = data_age;
        }
        dirtied = 0;
        data_age = 0;
    }

    bool isDirty() const {
        return dirtied != 0;
    }

    bool isClean() const {
        return dirtied == 0;
    }

    const std::string &getKey() const {
        return key;
    }

    const std::string &getValue() const {
        return value;
    }

    rel_time_t getExptime() const {
        return exptime;
    }

    uint32_t getFlags() const {
        return flags;
    }

    void setValue(const char *v, const size_t nv,
                  uint32_t newFlags, rel_time_t newExp, uint64_t theCas) {
        cas = theCas;
        flags = newFlags;
        exptime = newExp;
        value.assign(v, nv);
        markDirty();
    }

    uint64_t getCas() const {
        return cas;
    }

private:

    friend class HashTable;

    std::string key;
    std::string value;
    uint32_t flags;
    rel_time_t exptime;
    rel_time_t dirtied;
    rel_time_t data_age;
    StoredValue *next;
    uint64_t cas;
    DISALLOW_COPY_AND_ASSIGN(StoredValue);
};

typedef enum {
    NOT_FOUND, INVALID_CAS, WAS_CLEAN, WAS_DIRTY
} mutation_type_t;

class HashTableVisitor {
public:
    virtual ~HashTableVisitor() {}
    virtual void visit(StoredValue *v) = 0;
};

class HashTable {
public:

    // Construct with number of buckets and locks.
    HashTable(size_t s = 196613, size_t l = 193) {
        size = s;
        n_locks = l;
        active = true;
        values = (StoredValue**)calloc(s, sizeof(StoredValue**));
        mutexes = new Mutex[l];
    }

    ~HashTable() {
        clear();
        delete []mutexes;
        free(values);
    }

    void clear() {
        assert(active);
        for (int i = 0; i < (int)size; i++) {
            LockHolder lh(getMutex(i));
            while (values[i]) {
                StoredValue *v = values[i];
                values[i] = v->next;
                delete v;
            }
        }
    }

    StoredValue *find(std::string &key) {
        assert(active);
        int bucket_num = bucket(key);
        LockHolder lh(getMutex(bucket_num));
        return unlocked_find(key, bucket_num);
    }

    mutation_type_t set(const Item &val) {
        assert(active);
        mutation_type_t rv = NOT_FOUND;
        int bucket_num = bucket(val.getKey());
        LockHolder lh(getMutex(bucket_num));
        StoredValue *v = unlocked_find(val.getKey(), bucket_num);
        Item &itm = const_cast<Item&>(val);
        if (v) {
            if (val.getCas() != 0 && val.getCas() != v->getCas()) {
                return INVALID_CAS;
            }
            itm.setCas();
            rv = v->isClean() ? WAS_CLEAN : WAS_DIRTY;
            v->setValue(itm.getData(), itm.getNBytes(),
                        itm.getFlags(), itm.getExptime(),
                        itm.getCas());
        } else {
            if (itm.getCas() != 0) {
                return INVALID_CAS;
            }

            v = new StoredValue(itm, values[bucket_num]);
            values[bucket_num] = v;
        }
        return rv;
    }

    bool add(const Item &val, bool isDirty = true) {
        assert(active);
        int bucket_num = bucket(val.getKey());
        LockHolder lh(getMutex(bucket_num));
        StoredValue *v = unlocked_find(val.getKey(), bucket_num);
        if (v) {
            return false;
        } else {
            Item &itm = const_cast<Item&>(val);
            itm.setCas();
            v = new StoredValue(itm, values[bucket_num], isDirty);
            values[bucket_num] = v;
        }

        return true;
    }

    StoredValue *unlocked_find(const std::string &key, int bucket_num) {
        StoredValue *v = values[bucket_num];
        while (v) {
            if (key.compare(v->key) == 0) {
                return v;
            }
            v = v->next;
        }
        return NULL;
    }

    inline int bucket(const std::string &key) {
        assert(active);
        int h=5381;
        int i=0;
        const char *str = key.c_str();

        for(i=0; str[i] != 0x00; i++) {
            h = ((h << 5) + h) ^ str[i];
        }

        return abs(h) % (int)size;
    }

    // Get the mutex for a bucket (for doing your own lock management)
    inline Mutex &getMutex(int bucket_num) {
        assert(active);
        assert(bucket_num < (int)size);
        assert(bucket_num >= 0);
        int lock_num = bucket_num % (int)n_locks;
        assert(lock_num < (int)n_locks);
        assert(lock_num >= 0);
        return mutexes[lock_num];
    }

    // True if it existed
    bool del(const std::string &key) {
        assert(active);
        int bucket_num = bucket(key);
        LockHolder lh(getMutex(bucket_num));

        StoredValue *v = values[bucket_num];

        // Special case empty bucket.
        if (!v) {
            return false;
        }

        // Special case the first one
        if (key.compare(v->key) == 0) {
            values[bucket_num] = v->next;
            delete v;
            return true;
        }

        while (v->next) {
            if (key.compare(v->next->key) == 0) {
                StoredValue *tmp = v->next;
                v->next = v->next->next;
                delete tmp;
                return true;
            } else {
                v = v->next;
            }
        }

        return false;
    }

    void visit(HashTableVisitor &visitor) {
        for (int i = 0; i < (int)size; i++) {
            LockHolder lh(getMutex(i));
            StoredValue *v = values[i];
            while (v) {
                visitor.visit(v);
                v = v->next;
            }
        }
    }

private:
    size_t            size;
    size_t            n_locks;
    bool              active;
    StoredValue     **values;
    Mutex            *mutexes;

    DISALLOW_COPY_AND_ASSIGN(HashTable);
};

#endif /* STORED_VALUE_H */
<commit_msg>Fixed regression introduced in 7cdcbc40bd93c1389cdb0a92ba5784766250141c<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef STORED_VALUE_H
#define STORED_VALUE_H 1

#include "locks.hh"

extern "C" {
    extern rel_time_t (*ep_current_time)();
}

// Forward declaration for StoredValue
class HashTable;

class StoredValue {
public:
    StoredValue(const Item &itm, StoredValue *n) :
        key(itm.getKey()), value(const_cast<Item&>(itm).getData(), itm.getNBytes()),
        flags(itm.getFlags()), exptime(itm.getExptime()), dirtied(0), next(n),
        cas(itm.getCas())
    {
        markDirty();
    }

    StoredValue(const Item &itm, StoredValue *n, bool setDirty) :
        key(itm.getKey()), value(const_cast<Item&>(itm).getData(), itm.getNBytes()),
        flags(itm.getFlags()), exptime(itm.getExptime()), dirtied(0), next(n),
        cas(itm.getCas())
    {
        if (setDirty) {
            markDirty();
        } else {
            markClean(NULL, NULL);
        }
    }

    ~StoredValue() {
    }
    void markDirty() {
        data_age = ep_current_time();
        if (!isDirty()) {
            dirtied = data_age;
        }
    }

    void reDirty(rel_time_t dirtyAge, rel_time_t dataAge) {
        data_age = dataAge;
        dirtied = dirtyAge;
    }

    // returns time this object was dirtied.
    void markClean(rel_time_t *dirtyAge, rel_time_t *dataAge) {
        if (dirtyAge) {
            *dirtyAge = dirtied;
        }
        if (dataAge) {
            *dataAge = data_age;
        }
        dirtied = 0;
        data_age = 0;
    }

    bool isDirty() const {
        return dirtied != 0;
    }

    bool isClean() const {
        return dirtied == 0;
    }

    const std::string &getKey() const {
        return key;
    }

    const std::string &getValue() const {
        return value;
    }

    rel_time_t getExptime() const {
        return exptime;
    }

    uint32_t getFlags() const {
        return flags;
    }

    void setValue(const char *v, const size_t nv,
                  uint32_t newFlags, rel_time_t newExp, uint64_t theCas) {
        cas = theCas;
        flags = newFlags;
        exptime = newExp;
        value.assign(v, nv);
        markDirty();
    }

    uint64_t getCas() const {
        return cas;
    }

private:

    friend class HashTable;

    std::string key;
    std::string value;
    uint32_t flags;
    rel_time_t exptime;
    rel_time_t dirtied;
    rel_time_t data_age;
    StoredValue *next;
    uint64_t cas;
    DISALLOW_COPY_AND_ASSIGN(StoredValue);
};

typedef enum {
    NOT_FOUND, INVALID_CAS, WAS_CLEAN, WAS_DIRTY
} mutation_type_t;

class HashTableVisitor {
public:
    virtual ~HashTableVisitor() {}
    virtual void visit(StoredValue *v) = 0;
};

class HashTable {
public:

    // Construct with number of buckets and locks.
    HashTable(size_t s = 196613, size_t l = 193) {
        size = s;
        n_locks = l;
        active = true;
        values = (StoredValue**)calloc(s, sizeof(StoredValue**));
        mutexes = new Mutex[l];
    }

    ~HashTable() {
        clear();
        delete []mutexes;
        free(values);
    }

    void clear() {
        assert(active);
        for (int i = 0; i < (int)size; i++) {
            LockHolder lh(getMutex(i));
            while (values[i]) {
                StoredValue *v = values[i];
                values[i] = v->next;
                delete v;
            }
        }
    }

    StoredValue *find(std::string &key) {
        assert(active);
        int bucket_num = bucket(key);
        LockHolder lh(getMutex(bucket_num));
        return unlocked_find(key, bucket_num);
    }

    mutation_type_t set(const Item &val) {
        assert(active);
        mutation_type_t rv = NOT_FOUND;
        int bucket_num = bucket(val.getKey());
        LockHolder lh(getMutex(bucket_num));
        StoredValue *v = unlocked_find(val.getKey(), bucket_num);
        Item &itm = const_cast<Item&>(val);
        if (v) {
            if (val.getCas() != 0 && val.getCas() != v->getCas()) {
                return INVALID_CAS;
            }
            itm.setCas();
            rv = v->isClean() ? WAS_CLEAN : WAS_DIRTY;
            v->setValue(itm.getData(), itm.getNBytes(),
                        itm.getFlags(), itm.getExptime(),
                        itm.getCas());
        } else {
            if (itm.getCas() != 0) {
                return INVALID_CAS;
            }
            itm.setCas();
            v = new StoredValue(itm, values[bucket_num]);
            values[bucket_num] = v;
        }
        return rv;
    }

    bool add(const Item &val, bool isDirty = true) {
        assert(active);
        int bucket_num = bucket(val.getKey());
        LockHolder lh(getMutex(bucket_num));
        StoredValue *v = unlocked_find(val.getKey(), bucket_num);
        if (v) {
            return false;
        } else {
            Item &itm = const_cast<Item&>(val);
            itm.setCas();
            v = new StoredValue(itm, values[bucket_num], isDirty);
            values[bucket_num] = v;
        }

        return true;
    }

    StoredValue *unlocked_find(const std::string &key, int bucket_num) {
        StoredValue *v = values[bucket_num];
        while (v) {
            if (key.compare(v->key) == 0) {
                return v;
            }
            v = v->next;
        }
        return NULL;
    }

    inline int bucket(const std::string &key) {
        assert(active);
        int h=5381;
        int i=0;
        const char *str = key.c_str();

        for(i=0; str[i] != 0x00; i++) {
            h = ((h << 5) + h) ^ str[i];
        }

        return abs(h) % (int)size;
    }

    // Get the mutex for a bucket (for doing your own lock management)
    inline Mutex &getMutex(int bucket_num) {
        assert(active);
        assert(bucket_num < (int)size);
        assert(bucket_num >= 0);
        int lock_num = bucket_num % (int)n_locks;
        assert(lock_num < (int)n_locks);
        assert(lock_num >= 0);
        return mutexes[lock_num];
    }

    // True if it existed
    bool del(const std::string &key) {
        assert(active);
        int bucket_num = bucket(key);
        LockHolder lh(getMutex(bucket_num));

        StoredValue *v = values[bucket_num];

        // Special case empty bucket.
        if (!v) {
            return false;
        }

        // Special case the first one
        if (key.compare(v->key) == 0) {
            values[bucket_num] = v->next;
            delete v;
            return true;
        }

        while (v->next) {
            if (key.compare(v->next->key) == 0) {
                StoredValue *tmp = v->next;
                v->next = v->next->next;
                delete tmp;
                return true;
            } else {
                v = v->next;
            }
        }

        return false;
    }

    void visit(HashTableVisitor &visitor) {
        for (int i = 0; i < (int)size; i++) {
            LockHolder lh(getMutex(i));
            StoredValue *v = values[i];
            while (v) {
                visitor.visit(v);
                v = v->next;
            }
        }
    }

private:
    size_t            size;
    size_t            n_locks;
    bool              active;
    StoredValue     **values;
    Mutex            *mutexes;

    DISALLOW_COPY_AND_ASSIGN(HashTable);
};

#endif /* STORED_VALUE_H */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: UCBDeadPropertyValue.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 16:14:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UCBDEADPROPERTYVALUE_HXX_
#define _UCBDEADPROPERTYVALUE_HXX_

#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

namespace webdav_ucp
{

class UCBDeadPropertyValue
{
private:
    static const rtl::OUString aTypeString;
    static const rtl::OUString aTypeLong;
    static const rtl::OUString aTypeShort;
    static const rtl::OUString aTypeBoolean;
    static const rtl::OUString aTypeChar;
    static const rtl::OUString aTypeByte;
    static const rtl::OUString aTypeHyper;
    static const rtl::OUString aTypeFloat;
    static const rtl::OUString aTypeDouble;

    static const rtl::OUString aXMLPre;
    static const rtl::OUString aXMLMid;
    static const rtl::OUString aXMLEnd;

public:
    static bool supportsType( const com::sun::star::uno::Type & rType );

    static bool createFromXML( const rtl::OString & rInData,
                               com::sun::star::uno::Any & rOutData );
    static bool toXML( const com::sun::star::uno::Any & rInData,
                       rtl::OUString & rOutData );
};

}

#endif /* _UCBDEADPROPERTYVALUE_HXX_ */
<commit_msg>INTEGRATION: CWS changefileheader (1.5.184); FILE MERGED 2008/04/01 16:02:28 thb 1.5.184.2: #i85898# Stripping all external header guards 2008/03/31 15:30:32 rt 1.5.184.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: UCBDeadPropertyValue.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _UCBDEADPROPERTYVALUE_HXX_
#define _UCBDEADPROPERTYVALUE_HXX_

#include <rtl/string.hxx>
#include <com/sun/star/uno/Any.hxx>

namespace webdav_ucp
{

class UCBDeadPropertyValue
{
private:
    static const rtl::OUString aTypeString;
    static const rtl::OUString aTypeLong;
    static const rtl::OUString aTypeShort;
    static const rtl::OUString aTypeBoolean;
    static const rtl::OUString aTypeChar;
    static const rtl::OUString aTypeByte;
    static const rtl::OUString aTypeHyper;
    static const rtl::OUString aTypeFloat;
    static const rtl::OUString aTypeDouble;

    static const rtl::OUString aXMLPre;
    static const rtl::OUString aXMLMid;
    static const rtl::OUString aXMLEnd;

public:
    static bool supportsType( const com::sun::star::uno::Type & rType );

    static bool createFromXML( const rtl::OString & rInData,
                               com::sun::star::uno::Any & rOutData );
    static bool toXML( const com::sun::star::uno::Any & rInData,
                       rtl::OUString & rOutData );
};

}

#endif /* _UCBDEADPROPERTYVALUE_HXX_ */
<|endoftext|>


<commit_before>/* Copyright 2017 Istio Authors. All Rights Reserved.
 *
 * 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 "src/grpc_transport.h"

#include <grpc++/security/server_credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc/grpc.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <future>

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerReaderWriter;

using ::istio::mixer::v1::CheckRequest;
using ::istio::mixer::v1::CheckResponse;
using ::istio::mixer::v1::ReportRequest;
using ::istio::mixer::v1::ReportResponse;
using ::istio::mixer::v1::QuotaRequest;
using ::istio::mixer::v1::QuotaResponse;
using ::google::protobuf::util::Status;

using ::testing::Invoke;
using ::testing::_;

namespace istio {
namespace mixer_client {

// A fake Mixer gRPC server: just echo a response for each request.
class MockMixerServerImpl final : public ::istio::mixer::v1::Mixer::Service {
 public:
  grpc::Status Check(
      ServerContext* context,
      ServerReaderWriter<CheckResponse, CheckRequest>* stream) override {
    CheckRequest request;
    while (stream->Read(&request)) {
      CheckResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
  grpc::Status Report(
      ServerContext* context,
      ServerReaderWriter<ReportResponse, ReportRequest>* stream) override {
    ReportRequest request;
    while (stream->Read(&request)) {
      ReportResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
  grpc::Status Quota(
      ServerContext* context,
      ServerReaderWriter<QuotaResponse, QuotaRequest>* stream) override {
    QuotaRequest request;
    while (stream->Read(&request)) {
      QuotaResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
};

template <class T>
class MockReader : public ReadInterface<T> {
 public:
  MOCK_METHOD1_T(OnRead, void(const T&));
  MOCK_METHOD1_T(OnClose, void(const Status&));
};

class GrpcTransportTest : public ::testing::Test {
 public:
  void SetUp() {
    // TODO: pick a un-used port. If this port is used, the test will fail.
    std::string server_address("0.0.0.0:50051");
    ServerBuilder builder;
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterService(&service_);
    server_ = builder.BuildAndStart();

    grpc_transport_.reset(new GrpcTransport(server_address));
  }

  void TearDown() { server_->Shutdown(); }

  // server side
  MockMixerServerImpl service_;
  std::unique_ptr<Server> server_;

  // client side
  std::unique_ptr<GrpcTransport> grpc_transport_;
};

TEST_F(GrpcTransportTest, TestSuccessCheck) {
  MockReader<CheckResponse> mock_reader;
  auto writer = grpc_transport_->NewStream(&mock_reader);

  CheckResponse response;
  EXPECT_CALL(mock_reader, OnRead(_))
      .WillOnce(Invoke([&response](const CheckResponse& r) { response = r; }));

  std::promise<Status> status_promise;
  std::future<Status> status_future = status_promise.get_future();
  EXPECT_CALL(mock_reader, OnClose(_))
      .WillOnce(Invoke([&status_promise](Status status) {
        std::promise<Status> moved_promise(std::move(status_promise));
        if (!status.ok()) {
          GOOGLE_LOG(ERROR) << "Failed in OnClose: " << status.error_message();
        }
        moved_promise.set_value(status);
      }));

  CheckRequest request;
  request.set_request_index(111);
  writer->Write(request);

  // Close the stream
  writer->WritesDone();

  // Wait for OnClose() to be called.
  status_future.wait();
  EXPECT_TRUE(status_future.get().ok());
  EXPECT_EQ(response.request_index(), request.request_index());
}

}  // namespace mixer_client
}  // namespace istio
<commit_msg>Add WaitForServer in grpc_transport_test. (#37)<commit_after>/* Copyright 2017 Istio Authors. All Rights Reserved.
 *
 * 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 "src/grpc_transport.h"

#include <grpc++/security/server_credentials.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc/grpc.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <future>

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerReaderWriter;

using ::istio::mixer::v1::CheckRequest;
using ::istio::mixer::v1::CheckResponse;
using ::istio::mixer::v1::ReportRequest;
using ::istio::mixer::v1::ReportResponse;
using ::istio::mixer::v1::QuotaRequest;
using ::istio::mixer::v1::QuotaResponse;
using ::google::protobuf::util::Status;

using ::testing::Invoke;
using ::testing::_;

namespace istio {
namespace mixer_client {

// A fake Mixer gRPC server: just echo a response for each request.
class MockMixerServerImpl final : public ::istio::mixer::v1::Mixer::Service {
 public:
  grpc::Status Check(
      ServerContext* context,
      ServerReaderWriter<CheckResponse, CheckRequest>* stream) override {
    CheckRequest request;
    while (stream->Read(&request)) {
      CheckResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
  grpc::Status Report(
      ServerContext* context,
      ServerReaderWriter<ReportResponse, ReportRequest>* stream) override {
    ReportRequest request;
    while (stream->Read(&request)) {
      ReportResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
  grpc::Status Quota(
      ServerContext* context,
      ServerReaderWriter<QuotaResponse, QuotaRequest>* stream) override {
    QuotaRequest request;
    while (stream->Read(&request)) {
      QuotaResponse response;
      // Just echo it back with same request_index.
      response.set_request_index(request.request_index());
      stream->Write(response);
    }
    return grpc::Status::OK;
  }
};

// Wait for up to 10 seconds for channel to be connected.
void WaitForServer(const std::string& server) {
  auto channel = CreateChannel(server, ::grpc::InsecureChannelCredentials());
  channel->WaitForConnected(gpr_time_add(
      gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN)));
}

template <class T>
class MockReader : public ReadInterface<T> {
 public:
  MOCK_METHOD1_T(OnRead, void(const T&));
  MOCK_METHOD1_T(OnClose, void(const Status&));
};

class GrpcTransportTest : public ::testing::Test {
 public:
  void SetUp() {
    // TODO: pick a un-used port. If this port is used, the test will fail.
    std::string server_address("0.0.0.0:50051");
    ServerBuilder builder;
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterService(&service_);
    server_ = builder.BuildAndStart();

    WaitForServer(server_address);

    grpc_transport_.reset(new GrpcTransport(server_address));
  }

  void TearDown() { server_->Shutdown(); }

  // server side
  MockMixerServerImpl service_;
  std::unique_ptr<Server> server_;

  // client side
  std::unique_ptr<GrpcTransport> grpc_transport_;
};

TEST_F(GrpcTransportTest, TestSuccessCheck) {
  MockReader<CheckResponse> mock_reader;
  auto writer = grpc_transport_->NewStream(&mock_reader);

  CheckResponse response;
  EXPECT_CALL(mock_reader, OnRead(_))
      .WillOnce(Invoke([&response](const CheckResponse& r) { response = r; }));

  std::promise<Status> status_promise;
  std::future<Status> status_future = status_promise.get_future();
  EXPECT_CALL(mock_reader, OnClose(_))
      .WillOnce(Invoke([&status_promise](Status status) {
        std::promise<Status> moved_promise(std::move(status_promise));
        if (!status.ok()) {
          GOOGLE_LOG(ERROR) << "Failed in OnClose: " << status.error_message();
        }
        moved_promise.set_value(status);
      }));

  CheckRequest request;
  request.set_request_index(111);
  writer->Write(request);

  // Close the stream
  writer->WritesDone();

  // Wait for OnClose() to be called.
  status_future.wait();
  EXPECT_TRUE(status_future.get().ok());
  EXPECT_EQ(response.request_index(), request.request_index());
}

}  // namespace mixer_client
}  // namespace istio
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "type_check.h"
#include "environment.h"
#include "kernel_exception.h"
#include "normalize.h"
#include "instantiate.h"
#include "scoped_map.h"
#include "builtin.h"
#include "free_vars.h"

namespace lean {
/** \brief Auxiliary functional object used to implement infer_type. */
class type_checker::imp {
    typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache;

    environment     m_env;
    cache           m_cache;
    volatile bool   m_interrupted;

    expr lookup(context const & c, unsigned i) {
        auto p = lookup_ext(c, i);
        context_entry const & def = p.first;
        context const & def_c     = p.second;
        lean_assert(length(c) > length(def_c));
        return lift_free_vars(def.get_domain(), length(c) - length(def_c));
    }

    expr check_pi(expr const & e, expr const & s, context const & ctx) {
        if (is_pi(e))
            return e;
        expr r = normalize(e, m_env, ctx);
        if (is_pi(r))
            return r;
        throw function_expected_exception(m_env, ctx, s);
    }

    expr infer_pi(expr const & e, context const & ctx) {
        return check_pi(infer_type(e, ctx), e, ctx);
    }

public:
    imp(environment const & env):
        m_env(env) {
        m_interrupted = false;
    }

    level infer_universe(expr const & t, context const & ctx) {
        expr u = normalize(infer_type(t, ctx), m_env, ctx);
        if (is_type(u))
            return ty_level(u);
        if (u == Bool)
            return level();
        throw type_expected_exception(m_env, ctx, t);
    }

    expr infer_type(expr const & e, context const & ctx) {
        if (m_interrupted)
            throw interrupted();
        bool shared = false;
        if (is_shared(e)) {
            shared = true;
            auto it = m_cache.find(e);
            if (it != m_cache.end())
                return it->second;
        }

        expr r;
        switch (e.kind()) {
        case expr_kind::Constant:
            r = m_env.get_object(const_name(e)).get_type();
            break;
        case expr_kind::Var:
            r = lookup(ctx, var_idx(e));
            break;
        case expr_kind::Type:
            r = mk_type(ty_level(e) + 1);
            break;
        case expr_kind::App: {
            expr f_t     = infer_pi(arg(e, 0), ctx);
            unsigned i   = 1;
            unsigned num = num_args(e);
            lean_assert(num >= 2);
            while (true) {
                expr const & c = arg(e, i);
                expr c_t       = infer_type(c, ctx);
                if (!is_convertible(abst_domain(f_t), c_t, m_env, ctx))
                    throw app_type_mismatch_exception(m_env, ctx, e, i, abst_domain(f_t), c_t);
                if (closed(abst_body(f_t)))
                    f_t = abst_body(f_t);
                else if (closed(c))
                    f_t = instantiate_with_closed(abst_body(f_t), c);
                else
                    f_t = instantiate(abst_body(f_t), c);
                i++;
                if (i == num) {
                    r = f_t;
                    break;
                }
                check_pi(f_t, e, ctx);
            }
            break;
        }
        case expr_kind::Eq:
            infer_type(eq_lhs(e), ctx);
            infer_type(eq_rhs(e), ctx);
            r = mk_bool_type();
            break;
        case expr_kind::Lambda: {
            infer_universe(abst_domain(e), ctx);
            expr t;
            {
                cache::mk_scope sc(m_cache);
                t = infer_type(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
            }
            r = mk_pi(abst_name(e), abst_domain(e), t);
            break;
        }
        case expr_kind::Pi: {
            level l1 = infer_universe(abst_domain(e), ctx);
            level l2;
            {
                cache::mk_scope sc(m_cache);
                l2 = infer_universe(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
            }
            r = mk_type(max(l1, l2));
            break;
        }
        case expr_kind::Let: {
            expr lt = infer_type(let_value(e), ctx);
            {
                cache::mk_scope sc(m_cache);
                r = infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e)));
            }
            break;
        }
        case expr_kind::Value:
            r = to_value(e).get_type();
            break;
        }

        if (shared) {
            m_cache.insert(e, r);
        }
        return r;
    }

    void set_interrupt(bool flag) {
        m_interrupted = true;
    }

    void clear() {
        m_cache.clear();
    }
};

type_checker::type_checker(environment const & env):m_ptr(new imp(env)) {}
type_checker::~type_checker() {}
expr type_checker::infer_type(expr const & e, context const & ctx) { return m_ptr->infer_type(e, ctx); }
level type_checker::infer_universe(expr const & e, context const & ctx) { return m_ptr->infer_universe(e, ctx); }
void type_checker::clear() { m_ptr->clear(); }
void type_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }

expr  infer_type(expr const & e, environment const & env, context const & ctx) {
    return type_checker(env).infer_type(e, ctx);
}

level infer_universe(expr const & t, environment const & env, context const & ctx) {
    return type_checker(env).infer_universe(t, ctx);
}
}
<commit_msg>Use normalizer object in type checker. The idea is to make sure the interruption is propagated to normalizer.<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "type_check.h"
#include "environment.h"
#include "kernel_exception.h"
#include "normalize.h"
#include "instantiate.h"
#include "scoped_map.h"
#include "builtin.h"
#include "free_vars.h"

namespace lean {
/** \brief Auxiliary functional object used to implement infer_type. */
class type_checker::imp {
    typedef scoped_map<expr, expr, expr_hash, expr_eqp> cache;

    environment     m_env;
    cache           m_cache;
    normalizer      m_normalizer;
    volatile bool   m_interrupted;

    expr lookup(context const & c, unsigned i) {
        auto p = lookup_ext(c, i);
        context_entry const & def = p.first;
        context const & def_c     = p.second;
        lean_assert(length(c) > length(def_c));
        return lift_free_vars(def.get_domain(), length(c) - length(def_c));
    }

    expr check_pi(expr const & e, expr const & s, context const & ctx) {
        if (is_pi(e))
            return e;
        expr r = m_normalizer(e, ctx);
        if (is_pi(r))
            return r;
        throw function_expected_exception(m_env, ctx, s);
    }

    expr infer_pi(expr const & e, context const & ctx) {
        return check_pi(infer_type(e, ctx), e, ctx);
    }

public:
    imp(environment const & env):
        m_env(env),
        m_normalizer(env) {
        m_interrupted = false;
    }

    level infer_universe(expr const & t, context const & ctx) {
        expr u = m_normalizer(infer_type(t, ctx), ctx);
        if (is_type(u))
            return ty_level(u);
        if (u == Bool)
            return level();
        throw type_expected_exception(m_env, ctx, t);
    }

    expr infer_type(expr const & e, context const & ctx) {
        if (m_interrupted)
            throw interrupted();
        bool shared = false;
        if (is_shared(e)) {
            shared = true;
            auto it = m_cache.find(e);
            if (it != m_cache.end())
                return it->second;
        }

        expr r;
        switch (e.kind()) {
        case expr_kind::Constant:
            r = m_env.get_object(const_name(e)).get_type();
            break;
        case expr_kind::Var:
            r = lookup(ctx, var_idx(e));
            break;
        case expr_kind::Type:
            r = mk_type(ty_level(e) + 1);
            break;
        case expr_kind::App: {
            expr f_t     = infer_pi(arg(e, 0), ctx);
            unsigned i   = 1;
            unsigned num = num_args(e);
            lean_assert(num >= 2);
            while (true) {
                expr const & c = arg(e, i);
                expr c_t       = infer_type(c, ctx);
                if (!m_normalizer.is_convertible(abst_domain(f_t), c_t, ctx))
                    throw app_type_mismatch_exception(m_env, ctx, e, i, abst_domain(f_t), c_t);
                if (closed(abst_body(f_t)))
                    f_t = abst_body(f_t);
                else if (closed(c))
                    f_t = instantiate_with_closed(abst_body(f_t), c);
                else
                    f_t = instantiate(abst_body(f_t), c);
                i++;
                if (i == num) {
                    r = f_t;
                    break;
                }
                check_pi(f_t, e, ctx);
            }
            break;
        }
        case expr_kind::Eq:
            infer_type(eq_lhs(e), ctx);
            infer_type(eq_rhs(e), ctx);
            r = mk_bool_type();
            break;
        case expr_kind::Lambda: {
            infer_universe(abst_domain(e), ctx);
            expr t;
            {
                cache::mk_scope sc(m_cache);
                t = infer_type(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
            }
            r = mk_pi(abst_name(e), abst_domain(e), t);
            break;
        }
        case expr_kind::Pi: {
            level l1 = infer_universe(abst_domain(e), ctx);
            level l2;
            {
                cache::mk_scope sc(m_cache);
                l2 = infer_universe(abst_body(e), extend(ctx, abst_name(e), abst_domain(e)));
            }
            r = mk_type(max(l1, l2));
            break;
        }
        case expr_kind::Let: {
            expr lt = infer_type(let_value(e), ctx);
            {
                cache::mk_scope sc(m_cache);
                r = infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e)));
            }
            break;
        }
        case expr_kind::Value:
            r = to_value(e).get_type();
            break;
        }

        if (shared) {
            m_cache.insert(e, r);
        }
        return r;
    }

    void set_interrupt(bool flag) {
        m_interrupted = true;
        m_normalizer.set_interrupt(flag);
    }

    void clear() {
        m_cache.clear();
        m_normalizer.clear();
    }
};

type_checker::type_checker(environment const & env):m_ptr(new imp(env)) {}
type_checker::~type_checker() {}
expr type_checker::infer_type(expr const & e, context const & ctx) { return m_ptr->infer_type(e, ctx); }
level type_checker::infer_universe(expr const & e, context const & ctx) { return m_ptr->infer_universe(e, ctx); }
void type_checker::clear() { m_ptr->clear(); }
void type_checker::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }

expr  infer_type(expr const & e, environment const & env, context const & ctx) {
    return type_checker(env).infer_type(e, ctx);
}

level infer_universe(expr const & t, environment const & env, context const & ctx) {
    return type_checker(env).infer_universe(t, ctx);
}
}
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <regex>
#include <unordered_map>
#include "util.h"
#include "core.h"
#include "parser.h"
#include "interp.h"

#ifdef HAVE_SDL2

#include <SDL.h>

#endif

HostFn::HostFn(std::string name, size_t numParams, void* fptr)
: name(name),
  numParams(numParams),
  fptr(fptr)
{
}

Value HostFn::call0()
{
    assert (fptr);
    assert (numParams == 0);
    auto f0 = (Value(*)()) fptr;
    return f0();
}

Value HostFn::call1(Value arg0)
{
    assert (fptr);
    assert (numParams == 1);
    auto f1 = (Value(*)(Value)) fptr;
    return f1(arg0);
}

Value HostFn::call2(Value arg0, Value arg1)
{
    assert (fptr);
    assert (numParams == 2);
    auto f2 = (Value(*)(Value,Value)) fptr;
    return f2(arg0, arg1);
}

Value HostFn::call3(Value arg0, Value arg1, Value arg2)
{
    assert (fptr);
    assert (numParams == 3);
    auto f3 = (Value(*)(Value,Value,Value)) fptr;
    return f3(arg0, arg1, arg2);
}

void setHostFn(
    Object pkgObj,
    std::string name,
    size_t numParams,
    void* fptr
)
{
    auto fnObj = new HostFn(name, numParams, fptr);

    auto fnVal = Value((refptr)fnObj, TAG_HOSTFN);

    assert (!pkgObj.hasField(name));

    pkgObj.setField(name, fnVal);
}

void setInt32Const(
    Object pkgObj,
    std::string name,
    int32_t val
)
{
    auto intVal = Value::int32(val);

    assert (!pkgObj.hasField(name));

    pkgObj.setField(name, intVal);
}

//============================================================================
// core/io package
//============================================================================

Value print_int32(Value val)
{
    assert (val.isInt32());
    std::cout << (int32_t)val;
    return Value::UNDEF;
}

Value print_float32(Value val)
{
    assert (val.isFloat32());
    std::cout << (float)val;
    return Value::UNDEF;
}

Value print_str(Value val)
{
    assert (val.isString());
    std::cout << (std::string)val;
    return Value::UNDEF;
}

Value read_file(Value fileName)
{
    assert (fileName.isString());
    auto nameStr = (std::string)fileName;

    std::cout << "reading file: " << nameStr << std::endl;

    FILE* file = fopen(nameStr.c_str(), "r");

    if (!file)
    {
        printf("failed to open file\n");
        return Value::FALSE;
    }

    // Get the file size in bytes
    fseek(file, 0, SEEK_END);
    size_t len = ftell(file);
    fseek(file, 0, SEEK_SET);

    char* buf = (char*)malloc(len+1);

    // Read into the allocated buffer
    int read = fread(buf, 1, len, file);

    if (read != len)
    {
        printf("failed to read file");
        return Value::FALSE;
    }

    // Add a null terminator to the string
    buf[len] = '\0';

    // Close the input file
    fclose(file);

    return String(buf);
}

Value get_core_io_pkg()
{
    auto exports = Object::newObject(32);
    setHostFn(exports, "print_int32", 1, (void*)print_int32);
    setHostFn(exports, "print_float32", 1, (void*)print_float32);
    setHostFn(exports, "print_str"  , 1, (void*)print_str);
    setHostFn(exports, "read_file"  , 1, (void*)read_file);
    return exports;
}

//============================================================================
// core/window package
//============================================================================

#ifdef HAVE_SDL2

size_t width = 0;
size_t height = 0;

std::vector<uint8_t> pixelBuffer;

SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture* texture = nullptr;

Value create_window(
    Value titleVal,
    Value widthVal,
    Value heightVal
)
{
    SDL_Init(SDL_INIT_VIDEO);

    auto title = (std::string)titleVal;
    width = (size_t)(int32_t)widthVal;
    height = (size_t)(int32_t)heightVal;

    window = SDL_CreateWindow(
        title.c_str(),
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        width,
        height,
        0
    );

    renderer = SDL_CreateRenderer(window, -1, 0);

    texture = SDL_CreateTexture(
        renderer,
        SDL_PIXELFORMAT_RGBA8888,
        SDL_TEXTUREACCESS_STATIC,
        width,
        height
    );

    pixelBuffer.resize(width * height * 4, 0);

    SDL_ShowWindow(window);

    return Value::UNDEF;
}

Value destroy_window()
{
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    pixelBuffer.clear();

    return Value::UNDEF;
}

Value process_events()
{
    // FIXME
    // How do we know when quit happened? Return false then?
    // Maybe change go let users do the polling, write our own loop?

    SDL_Event event;

    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
            //quit = true;
            return Value::FALSE;
            break;

            default:
            break;
        }
    }

    return Value::TRUE;
}

Value draw_pixels(Value pixelsArray)
{
    auto pixels = (Array)pixelsArray;

    assert (pixels.length() == width * height * 3);

    for (size_t pixIdx = 0; pixIdx < width * height; ++pixIdx)
    {
        // SDL's RGBA888 is actually ABGR, because of course.
        pixelBuffer[4*pixIdx+0] = 255;
        pixelBuffer[4*pixIdx+1] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+2);
        pixelBuffer[4*pixIdx+2] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+1);
        pixelBuffer[4*pixIdx+3] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+0);
    }

    SDL_UpdateTexture(texture, NULL, &pixelBuffer[0], width * 4);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texture, NULL, NULL);
    SDL_RenderPresent(renderer);
    return Value::UNDEF;
}

#endif // HAVE_SDL2

Value get_core_window_pkg()
{
#ifdef HAVE_SDL2
    auto exports = Object::newObject(32);
    setHostFn(exports, "create_window"  , 3, (void*)create_window);
    setHostFn(exports, "destroy_window" , 0, (void*)destroy_window);
    setHostFn(exports, "process_events" , 0, (void*)process_events);
    setHostFn(exports, "draw_pixels"    , 1, (void*)draw_pixels);
    return exports;
#else
    return Value::UNDEF;
#endif
}

//============================================================================
// core/audio package
//============================================================================

#ifdef HAVE_SDL2

bool paused = true;

Value open_output_device(
    Value num_channels
)
{
    assert(num_channels.isInt32());

    SDL_Init(SDL_INIT_AUDIO);
    SDL_AudioSpec want, have;

    SDL_zero(want);
    want.freq = 44100;
    want.format = AUDIO_F32;
    want.channels = (uint8_t)(int32_t)num_channels;
    want.samples = 4096;
    want.callback = NULL; /* you wrote this function elsewhere. */

    return Value::int32((int32_t)SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE));
}

Value queue_samples(
    Value dev,
    Value samplesArray
)
{
    assert(dev.isInt32());
    assert(samplesArray.isArray());

    auto devID = (int32_t)dev;
    if (paused) {
        paused = false;
        SDL_PauseAudioDevice(devID, 0);
    }
    auto samples = (Array)samplesArray;
    if (samples.length() == 0) return Value::UNDEF;
    float samples_buf[samples.length()] = {0};

    for (int i = 0; i < samples.length(); i++)
    {
        auto elem = samples.getElem(i);
        if (elem.isFloat32())
        {
            float sample = (float)elem > 1.0f ? 1.0f : elem;
            sample = sample < -1.0f ? -1.0f : sample;
            samples_buf[i] = sample;
            continue;
        }
        assert(false && "the samples must be floats");

    }

    int error = SDL_QueueAudio(devID, samples_buf, sizeof(samples_buf));

    return Value::UNDEF;

}

Value get_queue_size(
    Value dev
)
{
    assert(dev.isInt32());

    auto devID = (int32_t)dev;
    return Value::int32((int32_t)SDL_GetQueuedAudioSize(devID));
}

Value close_output_device(
    Value dev
)
{
    assert(dev.isInt32());

    auto devID = (int32_t)dev;
    SDL_CloseAudioDevice(devID);

    return Value::UNDEF;
}

#endif // HAVE_SDL2

Value get_core_audio_pkg()
{
#ifdef HAVE_SDL2
    auto exports = Object::newObject(32);
    setHostFn(exports, "open_output_device" , 1, (void*)open_output_device);
    setHostFn(exports, "close_output_device", 1, (void*)close_output_device);
    setHostFn(exports, "queue_samples"      , 2, (void*)queue_samples);
    setHostFn(exports, "get_queue_size"     , 1, (void*)get_queue_size);
    return exports;
#else
    return Value::UNDEF;
#endif
}

//============================================================================

// Cache of loaded packages
std::unordered_map<std::string, Value> pkgCache;

/// Load a package based on its path
Object load(std::string pkgPath)
{
    Input input(pkgPath);

    Value exportVal;

    // Parse the language directive
    auto langPkgName = parseLang(input);

    // If a language package is specified
    if (langPkgName != "")
    {
        std::cout << "Loading language package" << std::endl;

        auto langPkgVal = import(langPkgName);

        if (!langPkgVal.isObject())
        {
            throw RunError("failed to load parser package");
        }

        auto langPkg = Object(langPkgVal);

        if (!langPkg.hasField("parse_input"))
        {
            throw RunError(
                "parser packages must export a parse_input function"
            );
        }

        // Create an object to pass the input data
        auto inputObj = Object::newObject();
        inputObj.setField("src_name", String(input.getSrcName()));
        inputObj.setField("src_string", String(input.getInputStr()));
        inputObj.setField("str_idx", Value::int32(input.getInputIdx()));
        inputObj.setField("line_no", Value::int32(input.getLineNo()));
        inputObj.setField("col_no", Value::int32(input.getColNo()));

        std::cout << "Calling parse_input" << std::endl;

        // Call the parse_input method exported by the parser package
        ValueVec args;
        args.push_back(inputObj);
        exportVal = callExportFn(langPkg, "parse_input", args);

        std::cout << "Returned from parse_input" << std::endl;
    }
    else
    {
        // Parse the package file contents
        exportVal = parseInput(input);
    }

    if (!exportVal.isObject())
    {
        throw RunError("exports value is not an object");
    }

    auto pkg = Object(exportVal);

    return pkg;
}

std::string findPkgPath(std::string pkgName)
{
    // If the package name directly maps to a relative path
    if (fileExists(pkgName))
        return pkgName;

    // Look in the package directory
    auto pkgPath = PKGS_DIR + pkgName + "/package";
    if (fileExists(pkgPath))
        return pkgPath;

    // Not found
    return "";
}

Value getCorePkg(std::string pkgName)
{
    // Internal/core packages
    if (pkgName == "core/io")
        return get_core_io_pkg();
    if (pkgName == "core/window")
        return get_core_window_pkg();
    if (pkgName == "core/audio")
        return get_core_audio_pkg();

    return Value::UNDEF;
}

/// Import a package based on its name, and perform caching
Value import(std::string pkgName)
{
    // Package names may only contain lowercase identifiers
    // separated by single forward slashes
    std::regex ex("([a-z0-9]+/)*[a-z0-9]+.?[a-z0-9]+");
    if(!regex_match(pkgName, ex))
    {
        std::cout << "invalid package name: \"" << pkgName << "\"" << std::endl;
        return Value::FALSE;
    }

    // If the package is already loaded
    auto itr = pkgCache.find(pkgName);
    if (itr != pkgCache.end())
    {
        return itr->second;
    }

    // If we can find a package file for this name
    auto pkgPath = findPkgPath(pkgName);
    if (pkgPath != "")
    {
        // Load the package file
        auto pkg = load(pkgPath);

        // Cache the package
        pkgCache[pkgName] = pkg;

        // Initialize the package
        if (pkg.hasField("init"))
        {
            callExportFn(pkg, "init");
        }

        return pkg;
    }

    // If we can find a core package for this name
    auto corePkg = getCorePkg(pkgName);
    if (corePkg != Value::UNDEF)
    {
        pkgCache[pkgName] = corePkg;
        return corePkg;
    }

    // Package not found
    return Value::UNDEF;
}
<commit_msg>Got rid of setInt32Const<commit_after>#include <cassert>
#include <iostream>
#include <regex>
#include <unordered_map>
#include "util.h"
#include "core.h"
#include "parser.h"
#include "interp.h"

#ifdef HAVE_SDL2

#include <SDL.h>

#endif

HostFn::HostFn(std::string name, size_t numParams, void* fptr)
: name(name),
  numParams(numParams),
  fptr(fptr)
{
}

Value HostFn::call0()
{
    assert (fptr);
    assert (numParams == 0);
    auto f0 = (Value(*)()) fptr;
    return f0();
}

Value HostFn::call1(Value arg0)
{
    assert (fptr);
    assert (numParams == 1);
    auto f1 = (Value(*)(Value)) fptr;
    return f1(arg0);
}

Value HostFn::call2(Value arg0, Value arg1)
{
    assert (fptr);
    assert (numParams == 2);
    auto f2 = (Value(*)(Value,Value)) fptr;
    return f2(arg0, arg1);
}

Value HostFn::call3(Value arg0, Value arg1, Value arg2)
{
    assert (fptr);
    assert (numParams == 3);
    auto f3 = (Value(*)(Value,Value,Value)) fptr;
    return f3(arg0, arg1, arg2);
}

void setHostFn(
    Object pkgObj,
    std::string name,
    size_t numParams,
    void* fptr
)
{
    auto fnObj = new HostFn(name, numParams, fptr);

    auto fnVal = Value((refptr)fnObj, TAG_HOSTFN);

    assert (!pkgObj.hasField(name));

    pkgObj.setField(name, fnVal);
}

//============================================================================
// core/io package
//============================================================================

Value print_int32(Value val)
{
    assert (val.isInt32());
    std::cout << (int32_t)val;
    return Value::UNDEF;
}

Value print_float32(Value val)
{
    assert (val.isFloat32());
    std::cout << (float)val;
    return Value::UNDEF;
}

Value print_str(Value val)
{
    assert (val.isString());
    std::cout << (std::string)val;
    return Value::UNDEF;
}

Value read_file(Value fileName)
{
    assert (fileName.isString());
    auto nameStr = (std::string)fileName;

    std::cout << "reading file: " << nameStr << std::endl;

    FILE* file = fopen(nameStr.c_str(), "r");

    if (!file)
    {
        printf("failed to open file\n");
        return Value::FALSE;
    }

    // Get the file size in bytes
    fseek(file, 0, SEEK_END);
    size_t len = ftell(file);
    fseek(file, 0, SEEK_SET);

    char* buf = (char*)malloc(len+1);

    // Read into the allocated buffer
    int read = fread(buf, 1, len, file);

    if (read != len)
    {
        printf("failed to read file");
        return Value::FALSE;
    }

    // Add a null terminator to the string
    buf[len] = '\0';

    // Close the input file
    fclose(file);

    return String(buf);
}

Value get_core_io_pkg()
{
    auto exports = Object::newObject(32);
    setHostFn(exports, "print_int32", 1, (void*)print_int32);
    setHostFn(exports, "print_float32", 1, (void*)print_float32);
    setHostFn(exports, "print_str"  , 1, (void*)print_str);
    setHostFn(exports, "read_file"  , 1, (void*)read_file);
    return exports;
}

//============================================================================
// core/window package
//============================================================================

#ifdef HAVE_SDL2

size_t width = 0;
size_t height = 0;

std::vector<uint8_t> pixelBuffer;

SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture* texture = nullptr;

Value create_window(
    Value titleVal,
    Value widthVal,
    Value heightVal
)
{
    SDL_Init(SDL_INIT_VIDEO);

    auto title = (std::string)titleVal;
    width = (size_t)(int32_t)widthVal;
    height = (size_t)(int32_t)heightVal;

    window = SDL_CreateWindow(
        title.c_str(),
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        width,
        height,
        0
    );

    renderer = SDL_CreateRenderer(window, -1, 0);

    texture = SDL_CreateTexture(
        renderer,
        SDL_PIXELFORMAT_RGBA8888,
        SDL_TEXTUREACCESS_STATIC,
        width,
        height
    );

    pixelBuffer.resize(width * height * 4, 0);

    SDL_ShowWindow(window);

    return Value::UNDEF;
}

Value destroy_window()
{
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    pixelBuffer.clear();

    return Value::UNDEF;
}

Value process_events()
{
    // FIXME
    // How do we know when quit happened? Return false then?
    // Maybe change go let users do the polling, write our own loop?

    SDL_Event event;

    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
            //quit = true;
            return Value::FALSE;
            break;

            default:
            break;
        }
    }

    return Value::TRUE;
}

Value draw_pixels(Value pixelsArray)
{
    auto pixels = (Array)pixelsArray;

    assert (pixels.length() == width * height * 3);

    for (size_t pixIdx = 0; pixIdx < width * height; ++pixIdx)
    {
        // SDL's RGBA888 is actually ABGR, because of course.
        pixelBuffer[4*pixIdx+0] = 255;
        pixelBuffer[4*pixIdx+1] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+2);
        pixelBuffer[4*pixIdx+2] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+1);
        pixelBuffer[4*pixIdx+3] = (uint8_t)(int32_t)pixels.getElem(3*pixIdx+0);
    }

    SDL_UpdateTexture(texture, NULL, &pixelBuffer[0], width * 4);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texture, NULL, NULL);
    SDL_RenderPresent(renderer);
    return Value::UNDEF;
}

#endif // HAVE_SDL2

Value get_core_window_pkg()
{
#ifdef HAVE_SDL2
    auto exports = Object::newObject(32);
    setHostFn(exports, "create_window"  , 3, (void*)create_window);
    setHostFn(exports, "destroy_window" , 0, (void*)destroy_window);
    setHostFn(exports, "process_events" , 0, (void*)process_events);
    setHostFn(exports, "draw_pixels"    , 1, (void*)draw_pixels);
    return exports;
#else
    return Value::UNDEF;
#endif
}

//============================================================================
// core/audio package
//============================================================================

#ifdef HAVE_SDL2

bool paused = true;

Value open_output_device(
    Value num_channels
)
{
    assert(num_channels.isInt32());

    SDL_Init(SDL_INIT_AUDIO);
    SDL_AudioSpec want, have;

    SDL_zero(want);
    want.freq = 44100;
    want.format = AUDIO_F32;
    want.channels = (uint8_t)(int32_t)num_channels;
    want.samples = 4096;
    want.callback = NULL; /* you wrote this function elsewhere. */

    return Value::int32((int32_t)SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE));
}

Value queue_samples(
    Value dev,
    Value samplesArray
)
{
    assert(dev.isInt32());
    assert(samplesArray.isArray());

    auto devID = (int32_t)dev;
    if (paused) {
        paused = false;
        SDL_PauseAudioDevice(devID, 0);
    }
    auto samples = (Array)samplesArray;
    if (samples.length() == 0) return Value::UNDEF;
    float samples_buf[samples.length()] = {0};

    for (int i = 0; i < samples.length(); i++)
    {
        auto elem = samples.getElem(i);
        if (elem.isFloat32())
        {
            float sample = (float)elem > 1.0f ? 1.0f : elem;
            sample = sample < -1.0f ? -1.0f : sample;
            samples_buf[i] = sample;
            continue;
        }
        assert(false && "the samples must be floats");

    }

    int error = SDL_QueueAudio(devID, samples_buf, sizeof(samples_buf));

    return Value::UNDEF;

}

Value get_queue_size(
    Value dev
)
{
    assert(dev.isInt32());

    auto devID = (int32_t)dev;
    return Value::int32((int32_t)SDL_GetQueuedAudioSize(devID));
}

Value close_output_device(
    Value dev
)
{
    assert(dev.isInt32());

    auto devID = (int32_t)dev;
    SDL_CloseAudioDevice(devID);

    return Value::UNDEF;
}

#endif // HAVE_SDL2

Value get_core_audio_pkg()
{
#ifdef HAVE_SDL2
    auto exports = Object::newObject(32);
    setHostFn(exports, "open_output_device" , 1, (void*)open_output_device);
    setHostFn(exports, "close_output_device", 1, (void*)close_output_device);
    setHostFn(exports, "queue_samples"      , 2, (void*)queue_samples);
    setHostFn(exports, "get_queue_size"     , 1, (void*)get_queue_size);
    return exports;
#else
    return Value::UNDEF;
#endif
}

//============================================================================

// Cache of loaded packages
std::unordered_map<std::string, Value> pkgCache;

/// Load a package based on its path
Object load(std::string pkgPath)
{
    Input input(pkgPath);

    Value exportVal;

    // Parse the language directive
    auto langPkgName = parseLang(input);

    // If a language package is specified
    if (langPkgName != "")
    {
        std::cout << "Loading language package" << std::endl;

        auto langPkgVal = import(langPkgName);

        if (!langPkgVal.isObject())
        {
            throw RunError("failed to load parser package");
        }

        auto langPkg = Object(langPkgVal);

        if (!langPkg.hasField("parse_input"))
        {
            throw RunError(
                "parser packages must export a parse_input function"
            );
        }

        // Create an object to pass the input data
        auto inputObj = Object::newObject();
        inputObj.setField("src_name", String(input.getSrcName()));
        inputObj.setField("src_string", String(input.getInputStr()));
        inputObj.setField("str_idx", Value::int32(input.getInputIdx()));
        inputObj.setField("line_no", Value::int32(input.getLineNo()));
        inputObj.setField("col_no", Value::int32(input.getColNo()));

        std::cout << "Calling parse_input" << std::endl;

        // Call the parse_input method exported by the parser package
        ValueVec args;
        args.push_back(inputObj);
        exportVal = callExportFn(langPkg, "parse_input", args);

        std::cout << "Returned from parse_input" << std::endl;
    }
    else
    {
        // Parse the package file contents
        exportVal = parseInput(input);
    }

    if (!exportVal.isObject())
    {
        throw RunError("exports value is not an object");
    }

    auto pkg = Object(exportVal);

    return pkg;
}

std::string findPkgPath(std::string pkgName)
{
    // If the package name directly maps to a relative path
    if (fileExists(pkgName))
        return pkgName;

    // Look in the package directory
    auto pkgPath = PKGS_DIR + pkgName + "/package";
    if (fileExists(pkgPath))
        return pkgPath;

    // Not found
    return "";
}

Value getCorePkg(std::string pkgName)
{
    // Internal/core packages
    if (pkgName == "core/io")
        return get_core_io_pkg();
    if (pkgName == "core/window")
        return get_core_window_pkg();
    if (pkgName == "core/audio")
        return get_core_audio_pkg();

    return Value::UNDEF;
}

/// Import a package based on its name, and perform caching
Value import(std::string pkgName)
{
    // Package names may only contain lowercase identifiers
    // separated by single forward slashes
    std::regex ex("([a-z0-9]+/)*[a-z0-9]+.?[a-z0-9]+");
    if(!regex_match(pkgName, ex))
    {
        std::cout << "invalid package name: \"" << pkgName << "\"" << std::endl;
        return Value::FALSE;
    }

    // If the package is already loaded
    auto itr = pkgCache.find(pkgName);
    if (itr != pkgCache.end())
    {
        return itr->second;
    }

    // If we can find a package file for this name
    auto pkgPath = findPkgPath(pkgName);
    if (pkgPath != "")
    {
        // Load the package file
        auto pkg = load(pkgPath);

        // Cache the package
        pkgCache[pkgName] = pkg;

        // Initialize the package
        if (pkg.hasField("init"))
        {
            callExportFn(pkg, "init");
        }

        return pkg;
    }

    // If we can find a core package for this name
    auto corePkg = getCorePkg(pkgName);
    if (corePkg != Value::UNDEF)
    {
        pkgCache[pkgName] = corePkg;
        return corePkg;
    }

    // Package not found
    return Value::UNDEF;
}
<|endoftext|>