<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Id$
 */

#if !defined(GRAMMARRESOLVER_HPP)
#define GRAMMARRESOLVER_HPP

#include <xercesc/util/RefHashTableOf.hpp>
#include <xercesc/util/StringPool.hpp>
#include <xercesc/validators/common/Grammar.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class DatatypeValidator;
class DatatypeValidatorFactory;
class XMLGrammarPool;
class XMLGrammarDescription;
class GrammarEntry;

/**
 * This class embodies the representation of a Grammar pool Resolver.
 * This class is called from the validator.
 *
 */

class VALIDATORS_EXPORT GrammarResolver : public XMemory
{
public:

    /** @name Constructor and Destructor */
    //@{
    /**
     *
     * Default Constructor
     */
    GrammarResolver(
                    XMLGrammarPool* const gramPool
                  , MemoryManager*  const manager = XMLPlatformUtils::fgMemoryManager
                    );
    /**
      * Destructor
      */
    ~GrammarResolver();

    //@}

    /** @name Getter methods */
    //@{
    /**
     * Retrieve the DatatypeValidator
     *
     * @param uriStr the namespace URI
     * @param typeName the type name
     * @return the DatatypeValidator associated with namespace & type name
     */
    DatatypeValidator* getDatatypeValidator(const XMLCh* const uriStr,
                                            const XMLCh* const typeName);

    /**
     * Retrieve the grammar that is associated with the specified namespace key
     *
     * @param  nameSpaceKey   Namespace key into Grammar pool
     * @return Grammar abstraction associated with the NameSpace key.
     */
    Grammar* getGrammar( const XMLCh* const nameSpaceKey ) ;
    Grammar* getGrammar( XMLGrammarDescription* const gramDesc ) ;

    /**
     * Get an enumeration of Grammar in the Grammar pool
     *
     * @return enumeration of Grammar in Grammar pool
     */
    RefHashTableOfEnumerator<GrammarEntry> getGrammarEnumerator() const;

    /**
     * Get a string pool of schema grammar element/attribute names/prefixes
     * (used by TraverseSchema)
     *
     * @return a string pool of schema grammar element/attribute names/prefixes
     */
    XMLStringPool* getStringPool();

    /**
     * Is the specified Namespace key in Grammar pool?
     *
     * @param  nameSpaceKey    Namespace key
     * @return True if Namespace key association is in the Grammar pool.
     */
    bool containsNameSpace( const XMLCh* const nameSpaceKey );

    //@}

    /** @name Setter methods */
    //@{

    /**
      * Set the 'Grammar caching' flag
      */
    void cacheGrammarFromParse(const bool newState);

    /**
      * Set the 'Use cached grammar' flag
      */
    void useCachedGrammarInParse(const bool newState);

    //@}

    /** @name GrammarResolver methods */
    //@{
    /**
     * Add the Grammar with Namespace Key associated to the Grammar Pool.
     * The Grammar will be owned by the Grammar Pool.
     *
     * @param  nameSpaceKey    Key to associate with Grammar abstraction
     * @param  grammarToAdopt  Grammar abstraction used by validator.
     */
    void putGrammar(const XMLCh* const nameSpaceKey, Grammar* const grammarToAdopt );
    void putGrammar(XMLGrammarDescription* const nameSpaceKey
                  , Grammar* const               grammarToAdopt );

    /**
     * Returns the Grammar with Namespace Key associated from the Grammar Pool
     * The Key entry is removed from the table (grammar is not deleted if
     * adopted - now owned by caller).
     *
     * @param  nameSpaceKey    Key to associate with Grammar abstraction
     */
    Grammar* orphanGrammar(const XMLCh* const nameSpaceKey);
    Grammar* orphanGrammar(XMLGrammarDescription* const nameSpaceKey);

    /**
     * Cache the grammars in fGrammarBucket to fCachedGrammarRegistry.
     * If a grammar with the same key is already cached, an exception is
     * thrown and none of the grammars will be cached.
     */
    void cacheGrammars();

    /**
     * Reset internal Namespace/Grammar registry.
     */
    void reset();
    void resetCachedGrammar();

    //@}

private:

    XMLGrammarDescription* getGrammarDescription(const XMLCh* const);

    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fStringPool            The string pool used by TraverseSchema to store
    //                         element/attribute names and prefixes.
    //
    //  fGrammarBucket       The parsed Grammar Pool, if no caching option.
    //
    //  fCachedGrammarRegistry The cached Grammar Pool.  It represents a
    //                         mapping between Namespace and a Grammar
    //
    //  fDataTypeReg           DatatypeValidatorFactory registery
    //
    //  fMemoryManager         Pluggable memory manager for dynamic memory
    //                         allocation/deallocation
    // -----------------------------------------------------------------------
    bool                       fCacheGrammar;
    bool                       fUseCachedGrammar;
    bool                       fGrammarPoolFromExternalApplication;
    XMLStringPool              fStringPool;
    RefHashTableOf<GrammarEntry>*   fGrammarBucket;
    DatatypeValidatorFactory*  fDataTypeReg;
    MemoryManager*             fMemoryManager;
    XMLGrammarPool*            fGrammarPool;
};

inline XMLStringPool* GrammarResolver::getStringPool() {

    return &fStringPool;
}

inline void GrammarResolver::useCachedGrammarInParse(const bool aValue)
{
    fUseCachedGrammar = aValue;
}

XERCES_CPP_NAMESPACE_END

#endif
<commit_msg>add getGrammarPool()<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Id$
 */

#if !defined(GRAMMARRESOLVER_HPP)
#define GRAMMARRESOLVER_HPP

#include <xercesc/util/RefHashTableOf.hpp>
#include <xercesc/util/StringPool.hpp>
#include <xercesc/validators/common/Grammar.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class DatatypeValidator;
class DatatypeValidatorFactory;
class XMLGrammarPool;
class XMLGrammarDescription;
class GrammarEntry;

/**
 * This class embodies the representation of a Grammar pool Resolver.
 * This class is called from the validator.
 *
 */

class VALIDATORS_EXPORT GrammarResolver : public XMemory
{
public:

    /** @name Constructor and Destructor */
    //@{
    /**
     *
     * Default Constructor
     */
    GrammarResolver(
                    XMLGrammarPool* const gramPool
                  , MemoryManager*  const manager = XMLPlatformUtils::fgMemoryManager
                    );
    /**
      * Destructor
      */
    ~GrammarResolver();

    //@}

    /** @name Getter methods */
    //@{
    /**
     * Retrieve the DatatypeValidator
     *
     * @param uriStr the namespace URI
     * @param typeName the type name
     * @return the DatatypeValidator associated with namespace & type name
     */
    DatatypeValidator* getDatatypeValidator(const XMLCh* const uriStr,
                                            const XMLCh* const typeName);

    /**
     * Retrieve the grammar that is associated with the specified namespace key
     *
     * @param  nameSpaceKey   Namespace key into Grammar pool
     * @return Grammar abstraction associated with the NameSpace key.
     */
    Grammar* getGrammar( const XMLCh* const nameSpaceKey ) ;
    Grammar* getGrammar( XMLGrammarDescription* const gramDesc ) ;

    /**
     * Get an enumeration of Grammar in the Grammar pool
     *
     * @return enumeration of Grammar in Grammar pool
     */
    RefHashTableOfEnumerator<GrammarEntry> getGrammarEnumerator() const;

    /**
     * Get a string pool of schema grammar element/attribute names/prefixes
     * (used by TraverseSchema)
     *
     * @return a string pool of schema grammar element/attribute names/prefixes
     */
    XMLStringPool* getStringPool();

    /**
     * Is the specified Namespace key in Grammar pool?
     *
     * @param  nameSpaceKey    Namespace key
     * @return True if Namespace key association is in the Grammar pool.
     */
    bool containsNameSpace( const XMLCh* const nameSpaceKey );

    inline XMLGrammarPool* const getGrammarPool() const;

    //@}

    /** @name Setter methods */
    //@{

    /**
      * Set the 'Grammar caching' flag
      */
    void cacheGrammarFromParse(const bool newState);

    /**
      * Set the 'Use cached grammar' flag
      */
    void useCachedGrammarInParse(const bool newState);

    //@}

    /** @name GrammarResolver methods */
    //@{
    /**
     * Add the Grammar with Namespace Key associated to the Grammar Pool.
     * The Grammar will be owned by the Grammar Pool.
     *
     * @param  nameSpaceKey    Key to associate with Grammar abstraction
     * @param  grammarToAdopt  Grammar abstraction used by validator.
     */
    void putGrammar(const XMLCh* const nameSpaceKey, Grammar* const grammarToAdopt );
    void putGrammar(XMLGrammarDescription* const nameSpaceKey
                  , Grammar* const               grammarToAdopt );

    /**
     * Returns the Grammar with Namespace Key associated from the Grammar Pool
     * The Key entry is removed from the table (grammar is not deleted if
     * adopted - now owned by caller).
     *
     * @param  nameSpaceKey    Key to associate with Grammar abstraction
     */
    Grammar* orphanGrammar(const XMLCh* const nameSpaceKey);
    Grammar* orphanGrammar(XMLGrammarDescription* const nameSpaceKey);

    /**
     * Cache the grammars in fGrammarBucket to fCachedGrammarRegistry.
     * If a grammar with the same key is already cached, an exception is
     * thrown and none of the grammars will be cached.
     */
    void cacheGrammars();

    /**
     * Reset internal Namespace/Grammar registry.
     */
    void reset();
    void resetCachedGrammar();

    //@}

private:

    XMLGrammarDescription* getGrammarDescription(const XMLCh* const);

    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fStringPool            The string pool used by TraverseSchema to store
    //                         element/attribute names and prefixes.
    //
    //  fGrammarBucket       The parsed Grammar Pool, if no caching option.
    //
    //  fCachedGrammarRegistry The cached Grammar Pool.  It represents a
    //                         mapping between Namespace and a Grammar
    //
    //  fDataTypeReg           DatatypeValidatorFactory registery
    //
    //  fMemoryManager         Pluggable memory manager for dynamic memory
    //                         allocation/deallocation
    // -----------------------------------------------------------------------
    bool                       fCacheGrammar;
    bool                       fUseCachedGrammar;
    bool                       fGrammarPoolFromExternalApplication;
    XMLStringPool              fStringPool;
    RefHashTableOf<GrammarEntry>*   fGrammarBucket;
    DatatypeValidatorFactory*  fDataTypeReg;
    MemoryManager*             fMemoryManager;
    XMLGrammarPool*            fGrammarPool;
};

inline XMLStringPool* GrammarResolver::getStringPool() {

    return &fStringPool;
}

inline void GrammarResolver::useCachedGrammarInParse(const bool aValue)
{
    fUseCachedGrammar = aValue;
}

inline XMLGrammarPool* const GrammarResolver::getGrammarPool() const
{
    return fGrammarPool;
}

XERCES_CPP_NAMESPACE_END

#endif
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 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.
 */

#include "ast.h"
#include "glsl_types.h"
#include "ir.h"

/**
 * If \c ir is a reference to an array for which we are tracking the max array
 * element accessed, track that the given element has been accessed.
 * Otherwise do nothing.
 *
 * This function also checks whether the array is a built-in array whose
 * maximum size is too small to accommodate the given index, and if so uses
 * loc and state to report the error.
 */
static void
update_max_array_access(ir_rvalue *ir, unsigned idx, YYLTYPE *loc,
                        struct _mesa_glsl_parse_state *state)
{
   if (ir_dereference_variable *deref_var = ir->as_dereference_variable()) {
      ir_variable *var = deref_var->var;
      if (idx > var->max_array_access) {
         var->max_array_access = idx;

         /* Check whether this access will, as a side effect, implicitly cause
          * the size of a built-in array to be too large.
          */
         check_builtin_array_max_size(var->name, idx+1, *loc, state);
      }
   }
}

ir_rvalue *
_mesa_ast_array_index_to_hir(void *mem_ctx,
			     struct _mesa_glsl_parse_state *state,
			     ir_rvalue *array, ir_rvalue *idx,
			     YYLTYPE &loc, YYLTYPE &idx_loc)
{
   if (!array->type->is_error()
       && !array->type->is_array()
       && !array->type->is_matrix()
       && !array->type->is_vector()) {
      _mesa_glsl_error(& idx_loc, state,
		       "cannot dereference non-array / non-matrix / "
		       "non-vector");
   }

   if (!idx->type->is_error()) {
      if (!idx->type->is_integer()) {
	 _mesa_glsl_error(& idx_loc, state, "array index must be integer type");
      } else if (!idx->type->is_scalar()) {
	 _mesa_glsl_error(& idx_loc, state, "array index must be scalar");
      }
   }

   /* If the array index is a constant expression and the array has a
    * declared size, ensure that the access is in-bounds.  If the array
    * index is not a constant expression, ensure that the array has a
    * declared size.
    */
   ir_constant *const const_index = idx->constant_expression_value();
   if (const_index != NULL && idx->type->is_integer()) {
      const int idx = const_index->value.i[0];
      const char *type_name = "error";
      unsigned bound = 0;

      /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
       *
       *    "It is illegal to declare an array with a size, and then
       *    later (in the same shader) index the same array with an
       *    integral constant expression greater than or equal to the
       *    declared size. It is also illegal to index an array with a
       *    negative constant expression."
       */
      if (array->type->is_matrix()) {
	 if (array->type->row_type()->vector_elements <= idx) {
	    type_name = "matrix";
	    bound = array->type->row_type()->vector_elements;
	 }
      } else if (array->type->is_vector()) {
	 if (array->type->vector_elements <= idx) {
	    type_name = "vector";
	    bound = array->type->vector_elements;
	 }
      } else {
	 /* glsl_type::array_size() returns 0 for non-array types.  This means
	  * that we don't need to verify that the type is an array before
	  * doing the bounds checking.
	  */
	 if ((array->type->array_size() > 0)
	     && (array->type->array_size() <= idx)) {
	    type_name = "array";
	    bound = array->type->array_size();
	 }
      }

      if (bound > 0) {
	 _mesa_glsl_error(& loc, state, "%s index must be < %u",
			  type_name, bound);
      } else if (idx < 0) {
	 _mesa_glsl_error(& loc, state, "%s index must be >= 0",
			  type_name);
      }

      if (array->type->is_array())
         update_max_array_access(array, idx, &loc, state);
   } else if (const_index == NULL && array->type->is_array()) {
      if (array->type->array_size() == 0) {
	 _mesa_glsl_error(&loc, state, "unsized array index must be constant");
      } else if (array->type->fields.array->is_interface()
                 && array->variable_referenced()->mode == ir_var_uniform) {
	 /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says:
	  *
	  *     "All indexes used to index a uniform block array must be
	  *     constant integral expressions."
	  */
	 _mesa_glsl_error(&loc, state,
			  "uniform block array index must be constant");
      } else {
	 /* whole_variable_referenced can return NULL if the array is a
	  * member of a structure.  In this case it is safe to not update
	  * the max_array_access field because it is never used for fields
	  * of structures.
	  */
	 ir_variable *v = array->whole_variable_referenced();
	 if (v != NULL)
	    v->max_array_access = array->type->array_size() - 1;
      }

      /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
       *
       *    "Samplers aggregated into arrays within a shader (using square
       *    brackets [ ]) can only be indexed with integral constant
       *    expressions [...]."
       *
       * This restriction was added in GLSL 1.30.  Shaders using earlier
       * version of the language should not be rejected by the compiler
       * front-end for using this construct.  This allows useful things such
       * as using a loop counter as the index to an array of samplers.  If the
       * loop in unrolled, the code should compile correctly.  Instead, emit a
       * warning.
       */
      if (array->type->element_type()->is_sampler()) {
	 if (!state->is_version(130, 100)) {
	    if (state->es_shader) {
	       _mesa_glsl_warning(&loc, state,
				  "sampler arrays indexed with non-constant "
				  "expressions is optional in %s",
				  state->get_version_string());
	    } else {
	       _mesa_glsl_warning(&loc, state,
				  "sampler arrays indexed with non-constant "
				  "expressions will be forbidden in GLSL 1.30 "
				  "and later");
	    }
	 } else {
	    _mesa_glsl_error(&loc, state,
			     "sampler arrays indexed with non-constant "
			     "expressions is forbidden in GLSL 1.30 and "
			     "later");
	 }
      }
   }

   /* After performing all of the error checking, generate the IR for the
    * expression.
    */
   if (array->type->is_array()
       || array->type->is_matrix()) {
      return new(mem_ctx) ir_dereference_array(array, idx);
   } else if (array->type->is_vector()) {
      return new(mem_ctx) ir_expression(ir_binop_vector_extract, array, idx);
   } else if (array->type->is_error()) {
      return array;
   } else {
      ir_rvalue *result = new(mem_ctx) ir_dereference_array(array, idx);
      result->type = glsl_type::error_type;

      return result;
   }
}
<commit_msg>glsl: Update ir_variable::max_ifc_array_access properly.<commit_after>/*
 * Copyright © 2010 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.
 */

#include "ast.h"
#include "glsl_types.h"
#include "ir.h"

/**
 * If \c ir is a reference to an array for which we are tracking the max array
 * element accessed, track that the given element has been accessed.
 * Otherwise do nothing.
 *
 * This function also checks whether the array is a built-in array whose
 * maximum size is too small to accommodate the given index, and if so uses
 * loc and state to report the error.
 */
static void
update_max_array_access(ir_rvalue *ir, unsigned idx, YYLTYPE *loc,
                        struct _mesa_glsl_parse_state *state)
{
   if (ir_dereference_variable *deref_var = ir->as_dereference_variable()) {
      ir_variable *var = deref_var->var;
      if (idx > var->max_array_access) {
         var->max_array_access = idx;

         /* Check whether this access will, as a side effect, implicitly cause
          * the size of a built-in array to be too large.
          */
         check_builtin_array_max_size(var->name, idx+1, *loc, state);
      }
   } else if (ir_dereference_record *deref_record =
              ir->as_dereference_record()) {
      /* There are two possibilities we need to consider:
       *
       * - Accessing an element of an array that is a member of a named
       *   interface block (e.g. ifc.foo[i])
       *
       * - Accessing an element of an array that is a member of a named
       *   interface block array (e.g. ifc[j].foo[i]).
       */
      ir_dereference_variable *deref_var =
         deref_record->record->as_dereference_variable();
      if (deref_var == NULL) {
         if (ir_dereference_array *deref_array =
             deref_record->record->as_dereference_array()) {
            deref_var = deref_array->array->as_dereference_variable();
         }
      }

      if (deref_var != NULL) {
         const glsl_type *interface_type =
            deref_var->var->get_interface_type();
         if (interface_type != NULL) {
            unsigned field_index =
               deref_record->record->type->field_index(deref_record->field);
            assert(field_index < interface_type->length);
            if (idx > deref_var->var->max_ifc_array_access[field_index]) {
               deref_var->var->max_ifc_array_access[field_index] = idx;

               /* Check whether this access will, as a side effect, implicitly
                * cause the size of a built-in array to be too large.
                */
               check_builtin_array_max_size(deref_record->field, idx+1, *loc,
                                            state);
            }
         }
      }
   }
}

ir_rvalue *
_mesa_ast_array_index_to_hir(void *mem_ctx,
			     struct _mesa_glsl_parse_state *state,
			     ir_rvalue *array, ir_rvalue *idx,
			     YYLTYPE &loc, YYLTYPE &idx_loc)
{
   if (!array->type->is_error()
       && !array->type->is_array()
       && !array->type->is_matrix()
       && !array->type->is_vector()) {
      _mesa_glsl_error(& idx_loc, state,
		       "cannot dereference non-array / non-matrix / "
		       "non-vector");
   }

   if (!idx->type->is_error()) {
      if (!idx->type->is_integer()) {
	 _mesa_glsl_error(& idx_loc, state, "array index must be integer type");
      } else if (!idx->type->is_scalar()) {
	 _mesa_glsl_error(& idx_loc, state, "array index must be scalar");
      }
   }

   /* If the array index is a constant expression and the array has a
    * declared size, ensure that the access is in-bounds.  If the array
    * index is not a constant expression, ensure that the array has a
    * declared size.
    */
   ir_constant *const const_index = idx->constant_expression_value();
   if (const_index != NULL && idx->type->is_integer()) {
      const int idx = const_index->value.i[0];
      const char *type_name = "error";
      unsigned bound = 0;

      /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
       *
       *    "It is illegal to declare an array with a size, and then
       *    later (in the same shader) index the same array with an
       *    integral constant expression greater than or equal to the
       *    declared size. It is also illegal to index an array with a
       *    negative constant expression."
       */
      if (array->type->is_matrix()) {
	 if (array->type->row_type()->vector_elements <= idx) {
	    type_name = "matrix";
	    bound = array->type->row_type()->vector_elements;
	 }
      } else if (array->type->is_vector()) {
	 if (array->type->vector_elements <= idx) {
	    type_name = "vector";
	    bound = array->type->vector_elements;
	 }
      } else {
	 /* glsl_type::array_size() returns 0 for non-array types.  This means
	  * that we don't need to verify that the type is an array before
	  * doing the bounds checking.
	  */
	 if ((array->type->array_size() > 0)
	     && (array->type->array_size() <= idx)) {
	    type_name = "array";
	    bound = array->type->array_size();
	 }
      }

      if (bound > 0) {
	 _mesa_glsl_error(& loc, state, "%s index must be < %u",
			  type_name, bound);
      } else if (idx < 0) {
	 _mesa_glsl_error(& loc, state, "%s index must be >= 0",
			  type_name);
      }

      if (array->type->is_array())
         update_max_array_access(array, idx, &loc, state);
   } else if (const_index == NULL && array->type->is_array()) {
      if (array->type->array_size() == 0) {
	 _mesa_glsl_error(&loc, state, "unsized array index must be constant");
      } else if (array->type->fields.array->is_interface()
                 && array->variable_referenced()->mode == ir_var_uniform) {
	 /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says:
	  *
	  *     "All indexes used to index a uniform block array must be
	  *     constant integral expressions."
	  */
	 _mesa_glsl_error(&loc, state,
			  "uniform block array index must be constant");
      } else {
	 /* whole_variable_referenced can return NULL if the array is a
	  * member of a structure.  In this case it is safe to not update
	  * the max_array_access field because it is never used for fields
	  * of structures.
	  */
	 ir_variable *v = array->whole_variable_referenced();
	 if (v != NULL)
	    v->max_array_access = array->type->array_size() - 1;
      }

      /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
       *
       *    "Samplers aggregated into arrays within a shader (using square
       *    brackets [ ]) can only be indexed with integral constant
       *    expressions [...]."
       *
       * This restriction was added in GLSL 1.30.  Shaders using earlier
       * version of the language should not be rejected by the compiler
       * front-end for using this construct.  This allows useful things such
       * as using a loop counter as the index to an array of samplers.  If the
       * loop in unrolled, the code should compile correctly.  Instead, emit a
       * warning.
       */
      if (array->type->element_type()->is_sampler()) {
	 if (!state->is_version(130, 100)) {
	    if (state->es_shader) {
	       _mesa_glsl_warning(&loc, state,
				  "sampler arrays indexed with non-constant "
				  "expressions is optional in %s",
				  state->get_version_string());
	    } else {
	       _mesa_glsl_warning(&loc, state,
				  "sampler arrays indexed with non-constant "
				  "expressions will be forbidden in GLSL 1.30 "
				  "and later");
	    }
	 } else {
	    _mesa_glsl_error(&loc, state,
			     "sampler arrays indexed with non-constant "
			     "expressions is forbidden in GLSL 1.30 and "
			     "later");
	 }
      }
   }

   /* After performing all of the error checking, generate the IR for the
    * expression.
    */
   if (array->type->is_array()
       || array->type->is_matrix()) {
      return new(mem_ctx) ir_dereference_array(array, idx);
   } else if (array->type->is_vector()) {
      return new(mem_ctx) ir_expression(ir_binop_vector_extract, array, idx);
   } else if (array->type->is_error()) {
      return array;
   } else {
      ir_rvalue *result = new(mem_ctx) ir_dereference_array(array, idx);
      result->type = glsl_type::error_type;

      return result;
   }
}
<|endoftext|>


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

#ifndef RS_LAZY_FLAT_SET
#define RS_LAZY_FLAT_SET

#include <vector>
#include <algorithm>
#include <type_traits>

namespace rs {

template <class Key, class Less = std::less<Key>, class Equal = std::equal_to<Key>, class Alloc = std::allocator<Key>>
class LazyFlatSet {
public:
    using base_collection = typename std::vector<Key, Alloc>;
    using size_type = typename base_collection::size_type;
    using iterator = typename base_collection::iterator;
    using const_iterator = typename base_collection::const_iterator;
    using value_type = Key;
    using reference = typename std::conditional<std::is_fundamental<Key>::value || std::is_pointer<Key>::value, value_type, value_type&>::type;
    using const_reference = typename std::conditional<std::is_fundamental<Key>::value || std::is_pointer<Key>::value, value_type, const value_type&>::type;

    LazyFlatSet(unsigned maxUnsortedEntries = 16, unsigned maxNurseryEntries = 1024) :
            maxUnsortedEntries_(maxUnsortedEntries), maxNurseryEntries_(maxNurseryEntries) {
        unsorted_.reserve(maxUnsortedEntries);
    }

    void insert(const value_type& k) {
        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            *iter = k;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                *iter = k;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    *iter = k;
                } else {
                    if (unsorted_.size() == maxUnsortedEntries_) {
                        flushUnsorted();
                    }

                    unsorted_.push_back(k);
                }
            }
        }
    }

    bool empty() const {
        return coll_.empty() && nursery_.empty() && unsorted_.empty();
    }

    void clear() {
        coll_.clear();
        nursery_.clear();
        unsorted_.clear();
    }

    void reserve(size_type n) {
        coll_.reserve(n);
    }

    size_type size() const {
        return coll_.size() + nursery_.size() + unsorted_.size();
    }

    void shrink_to_fit() {
        flush();
        nursery_.shrink_to_fit();
        coll_.shrink_to_fit();
    }

    size_type count(const value_type& k) const {
        size_type found = 0;

        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            found = 1;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                found = 1;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    found = 1;
                }
            }
        }

         return found;
    }

    bool find(const value_type& k, value_type& v) {
        auto found = false;

        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            v = *iter;
            found = true;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                v = *iter;
                found = true;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    v = *iter;
                    found = true;
                }
            }
        }

         return found;
    }

    const_reference operator[](size_type n) const {
        flush();
        return coll_[n];
    }

    const_iterator cbegin() const {
        flush();
        return coll_.cbegin();
    }

    const_iterator cend() const {
        flush();
        return coll_.cend();
    }

    const value_type* data() const {
        flush();
        return coll_.data();
    }

private:
    void sort(base_collection& coll) const {
        std::sort(coll.begin(), coll.end(), Less{});
    }

    iterator lower_bound(base_collection& coll, const value_type& k) const {
        return std::lower_bound(coll.begin(), coll.end(), k, Less{});
    }

    iterator lower_bound_equals(base_collection& coll, const value_type& k) const {
        auto iter = lower_bound(coll, k);
        return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
    }

    iterator upper_bound(base_collection& coll, const value_type& k) const {
        return std::upper_bound(coll.begin(), coll.end(), k, Less{});
    }

    iterator upper_bound_equals(base_collection& coll, const value_type& k) const {
        auto iter = upper_bound(coll, k);
        return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
    }

    iterator search_unsorted(base_collection& coll, const value_type& k) const {
        return std::search_n(coll.begin(), coll.end(), 1, k, Equal{});
    }

    void flush() const {
        flushUnsorted();
        flushNursery();
    }

    void flushUnsorted() const {
        const auto unsortedSize = unsorted_.size();
        if (unsortedSize > 0) {
            if ((nursery_.size() + unsortedSize) >= maxNurseryEntries_) {
                flushNursery();
            }

            sort(unsorted_);
            merge(unsorted_, nursery_);
            unsorted_.clear();
        }
    }

    void flushNursery() const {
        if (nursery_.size() > 0) {
            merge(nursery_, coll_);
            nursery_.clear();
        }
    }

    // TODO: optimize the range insert
    void merge(base_collection& source, base_collection& target) const {
        if (source.size() > 0) {
            auto sourceStart = source.cbegin(), sourceIter = sourceStart;
            auto targetStart = upper_bound(target, *sourceIter++);

            if (targetStart != target.end()) {
                for (; sourceIter != source.cend(); ++sourceIter) {
                    auto targetIter = upper_bound(target, *sourceIter);
                    if (targetStart != targetIter) {
                        auto targetDelta = targetIter - target.begin();
                        target.insert(targetStart, sourceStart, sourceIter);
                        sourceStart = sourceIter;
                        targetStart = target.begin() + targetDelta;
                    }
                }
            } else {
                sourceIter = source.end();
            }

            if (sourceStart != sourceIter) {
                target.insert(targetStart, sourceStart, sourceIter);
            }
        }
    }

    const unsigned maxUnsortedEntries_;
    const unsigned maxNurseryEntries_;

    mutable base_collection coll_;
    mutable base_collection nursery_;
    mutable base_collection unsorted_;
};

}

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

#ifndef RS_LAZY_FLAT_SET
#define RS_LAZY_FLAT_SET

#include <vector>
#include <algorithm>
#include <type_traits>

namespace rs {

template <class Key, class Less = std::less<Key>, class Equal = std::equal_to<Key>, class Alloc = std::allocator<Key>>
class LazyFlatSet {
public:
    using base_collection = typename std::vector<Key, Alloc>;
    using size_type = typename base_collection::size_type;
    using iterator = typename base_collection::iterator;
    using const_iterator = typename base_collection::const_iterator;
    using value_type = Key;
    using reference = typename std::conditional<std::is_fundamental<Key>::value || std::is_pointer<Key>::value, value_type, value_type&>::type;
    using const_reference = typename std::conditional<std::is_fundamental<Key>::value || std::is_pointer<Key>::value, value_type, const value_type&>::type;

    LazyFlatSet(unsigned maxUnsortedEntries = 16, unsigned maxNurseryEntries = 1024) :
            maxUnsortedEntries_(maxUnsortedEntries), maxNurseryEntries_(maxNurseryEntries) {
        unsorted_.reserve(maxUnsortedEntries);
    }

    void insert(const value_type& k) {
        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            *iter = k;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                *iter = k;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    *iter = k;
                } else {
                    if (unsorted_.size() == maxUnsortedEntries_) {
                        flushUnsorted();
                    }

                    unsorted_.push_back(k);
                }
            }
        }
    }

    bool empty() const {
        return coll_.empty() && nursery_.empty() && unsorted_.empty();
    }

    void clear() {
        coll_.clear();
        nursery_.clear();
        unsorted_.clear();
    }

    void reserve(size_type n) {
        coll_.reserve(n);
    }

    size_type size() const {
        return coll_.size() + nursery_.size() + unsorted_.size();
    }

    void shrink_to_fit() {
        flush();
        nursery_.shrink_to_fit();
        coll_.shrink_to_fit();
    }

    size_type count(const value_type& k) const {
        size_type found = 0;

        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            found = 1;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                found = 1;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    found = 1;
                }
            }
        }

        return found;
    }

    bool find(const value_type& k, value_type& v) {
        auto found = false;

        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            v = *iter;
            found = true;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                v = *iter;
                found = true;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    v = *iter;
                    found = true;
                }
            }
        }

         return found;
    }

    const_reference operator[](size_type n) const {
        flush();
        return coll_[n];
    }

    const_iterator cbegin() const {
        flush();
        return coll_.cbegin();
    }

    const_iterator cend() const {
        flush();
        return coll_.cend();
    }

    const value_type* data() const {
        flush();
        return coll_.data();
    }

    size_type erase(const value_type& k) {
        size_type count = 0;

        auto iter = lower_bound_equals(coll_, k);
        if (iter != coll_.end()) {
            coll_.erase(iter);
            count = 1;
        } else {
            iter = lower_bound_equals(nursery_, k);
            if (iter != nursery_.end()) {
                nursery_.erase(iter);
                count = 1;
            } else {
                iter = search_unsorted(unsorted_, k);
                if (iter != unsorted_.end()) {
                    unsorted_.erase(iter);
                    count = 1;
                }
            }
        }

        return count;
    }

private:
    void sort(base_collection& coll) const {
        std::sort(coll.begin(), coll.end(), Less{});
    }

    iterator lower_bound(base_collection& coll, const value_type& k) const {
        return std::lower_bound(coll.begin(), coll.end(), k, Less{});
    }

    iterator lower_bound_equals(base_collection& coll, const value_type& k) const {
        auto iter = lower_bound(coll, k);
        return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
    }

    iterator upper_bound(base_collection& coll, const value_type& k) const {
        return std::upper_bound(coll.begin(), coll.end(), k, Less{});
    }

    iterator upper_bound_equals(base_collection& coll, const value_type& k) const {
        auto iter = upper_bound(coll, k);
        return iter != coll.end() && Equal{}(*iter, k) ? iter : coll.end();
    }

    iterator search_unsorted(base_collection& coll, const value_type& k) const {
        return std::search_n(coll.begin(), coll.end(), 1, k, Equal{});
    }

    void flush() const {
        flushUnsorted();
        flushNursery();
    }

    void flushUnsorted() const {
        const auto unsortedSize = unsorted_.size();
        if (unsortedSize > 0) {
            if ((nursery_.size() + unsortedSize) >= maxNurseryEntries_) {
                flushNursery();
            }

            sort(unsorted_);
            merge(unsorted_, nursery_);
            unsorted_.clear();
        }
    }

    void flushNursery() const {
        if (nursery_.size() > 0) {
            merge(nursery_, coll_);
            nursery_.clear();
        }
    }

    // TODO: optimize the range insert
    void merge(base_collection& source, base_collection& target) const {
        if (source.size() > 0) {
            auto sourceStart = source.cbegin(), sourceIter = sourceStart;
            auto targetStart = upper_bound(target, *sourceIter++);

            if (targetStart != target.end()) {
                for (; sourceIter != source.cend(); ++sourceIter) {
                    auto targetIter = upper_bound(target, *sourceIter);
                    if (targetStart != targetIter) {
                        auto targetDelta = targetIter - target.begin();
                        target.insert(targetStart, sourceStart, sourceIter);
                        sourceStart = sourceIter;
                        targetStart = target.begin() + targetDelta;
                    }
                }
            } else {
                sourceIter = source.end();
            }

            if (sourceStart != sourceIter) {
                target.insert(targetStart, sourceStart, sourceIter);
            }
        }
    }

    const unsigned maxUnsortedEntries_;
    const unsigned maxNurseryEntries_;

    mutable base_collection coll_;
    mutable base_collection nursery_;
    mutable base_collection unsorted_;
};

}

#endif<|endoftext|>


<commit_before>/*
  Copyright (C) 2015 Marcus Soll
  All rights reserved.

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Jolla Ltd nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "batch_save.h"
#include <QDebug>
#include <QVariant>

batch_save::batch_save(QSqlDatabase settings, QObject *parent) :
    QObject(parent),
    _settings(settings),
    _settings_query(settings)
{
}

bool batch_save::start_transaction()
{
    _settings_query.clear();
    if(!_settings.transaction())
    {
        qCritical() << "ERROR in " __FILE__ << " " << __LINE__ << ": Can not start transaction";
        return false;
    }
    return true;
}

bool batch_save::save(QString literal)
{
    QString s = QString("INSERT OR IGNORE INTO saved_kanji (literal) VALUES (?)");
    _settings_query.prepare(s);
    _settings_query.addBindValue(literal);
    if(!_settings_query.exec())
    {
        QString error = s.append(": ").append(_settings_query.lastError().text());
        qWarning() << error;
        _settings_query.clear();
        return false;
    }
    return true;
}

bool batch_save::commit()
{
    _settings_query.clear();
    if(!_settings.commit())
    {
        qCritical() << "ERROR in " __FILE__ << " " << __LINE__ << ": Can not commit";
        return false;
    }
    return true;
}

bool batch_save::save_array(QVariantList array)
{
    if(!start_transaction())
    {
        return false;
    }
    foreach (QVariant s, array)
    {
        if(!save(s.toString()))
        {
            return false;
        }
    }
    if(!commit())
    {
        return false;
    }
    return true;
}
<commit_msg>Query reset corrected in batch_save.commit()<commit_after>/*
  Copyright (C) 2015 Marcus Soll
  All rights reserved.

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Jolla Ltd nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "batch_save.h"
#include <QDebug>
#include <QVariant>

batch_save::batch_save(QSqlDatabase settings, QObject *parent) :
    QObject(parent),
    _settings(settings),
    _settings_query(settings)
{
}

bool batch_save::start_transaction()
{
    _settings_query.clear();
    if(!_settings.transaction())
    {
        qCritical() << "ERROR in " __FILE__ << " " << __LINE__ << ": Can not start transaction";
        return false;
    }
    return true;
}

bool batch_save::save(QString literal)
{
    QString s = QString("INSERT OR IGNORE INTO saved_kanji (literal) VALUES (?)");
    _settings_query.prepare(s);
    _settings_query.addBindValue(literal);
    if(!_settings_query.exec())
    {
        QString error = s.append(": ").append(_settings_query.lastError().text());
        qWarning() << error;
        _settings_query.clear();
        return false;
    }
    return true;
}

bool batch_save::commit()
{
    if(!_settings.commit())
    {
        qCritical() << "ERROR in " __FILE__ << " " << __LINE__ << ": Can not commit";
        _settings_query.clear();
        return false;
    }
    _settings_query.clear();
    return true;
}

bool batch_save::save_array(QVariantList array)
{
    if(!start_transaction())
    {
        return false;
    }
    foreach (QVariant s, array)
    {
        if(!save(s.toString()))
        {
            return false;
        }
    }
    if(!commit())
    {
        return false;
    }
    return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// C
#include <cstdlib>

// C++
#include <iostream>

// STL
#include <cctype>
#include <memory>
#include <vector>

// e
#include <e/slice.h>

// LevelDB
#include <leveldb/db.h>
#include <leveldb/filter_policy.h>

void
decode(const char* data, size_t data_sz, std::vector<char>* out)
{
    out->resize(data_sz * 4 + 1);
    char* ptr = &out->front();

    for (size_t i = 0; i < data_sz; ++i)
    {
        if (isalnum(data[i]) ||
            (ispunct(data[i]) && data[i] != '\'') ||
            data[i] == ' ')
        {
            *ptr = data[i];
            ++ptr;
        }
        else if (data[i] == '\n')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'n';
            ++ptr;
        }
        else if (data[i] == '\r')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'r';
            ++ptr;
        }
        else if (data[i] == '\t')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 't';
            ++ptr;
        }
        else if (data[i] == '\'')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = '\'';
            ++ptr;
        }
        else
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'x';
            ++ptr;
            sprintf(ptr, "%02x", data[i]);
            ptr += 2;
        }
    }
}

int
main(int argc, const char* argv[])
{
    for (int i = 1; i < argc; ++i)
    {
        std::cout << "dumping db at " << argv[i] << std::endl;
        leveldb::Options oopts;
        oopts.create_if_missing = false;
        oopts.filter_policy = leveldb::NewBloomFilterPolicy(10);
        std::string name(argv[i]);
        leveldb::DB* db;
        leveldb::Status st = leveldb::DB::Open(oopts, name, &db);

        if (!st.ok())
        {
            std::cout << "could not open LevelDB: " << st.ToString() << std::endl;
            continue;
        }

        std::auto_ptr<leveldb::Iterator> it(db->NewIterator(leveldb::ReadOptions()));
        it->SeekToFirst();

        while (it->Valid())
        {
            std::vector<char> k;
            std::vector<char> v;
            decode(it->key().data(), it->key().size(), &k);
            decode(it->value().data(), it->value().size(), &v);
            std::cout << "\"" << &k[0] << "\" -> \"" << &v[0] << "\"\n";
            it->Next();
        }

        std::cout << std::flush;
        it.reset();
        delete db;
    }
}
<commit_msg>Fix leveldb-dump output<commit_after>// Copyright (c) 2012, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// C
#include <cstdlib>

// C++
#include <iostream>

// STL
#include <cctype>
#include <memory>
#include <vector>

// e
#include <e/slice.h>

// LevelDB
#include <leveldb/db.h>
#include <leveldb/filter_policy.h>

void
decode(const char* data, size_t data_sz, std::vector<char>* out)
{
    out->resize(data_sz * 4 + 1);
    char* ptr = &out->front();

    for (size_t i = 0; i < data_sz; ++i)
    {
        if (isalnum(data[i]) ||
            (ispunct(data[i]) && data[i] != '\'') ||
            data[i] == ' ')
        {
            *ptr = data[i];
            ++ptr;
        }
        else if (data[i] == '\n')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'n';
            ++ptr;
        }
        else if (data[i] == '\r')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'r';
            ++ptr;
        }
        else if (data[i] == '\t')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 't';
            ++ptr;
        }
        else if (data[i] == '\'')
        {
            *ptr = '\\';
            ++ptr;
            *ptr = '\'';
            ++ptr;
        }
        else
        {
            *ptr = '\\';
            ++ptr;
            *ptr = 'x';
            ++ptr;
            sprintf(ptr, "%02x", data[i] & 0xff);
            ptr += 2;
        }
    }
}

int
main(int argc, const char* argv[])
{
    for (int i = 1; i < argc; ++i)
    {
        std::cout << "dumping db at " << argv[i] << std::endl;
        leveldb::Options oopts;
        oopts.create_if_missing = false;
        oopts.filter_policy = leveldb::NewBloomFilterPolicy(10);
        std::string name(argv[i]);
        leveldb::DB* db;
        leveldb::Status st = leveldb::DB::Open(oopts, name, &db);

        if (!st.ok())
        {
            std::cout << "could not open LevelDB: " << st.ToString() << std::endl;
            continue;
        }

        std::auto_ptr<leveldb::Iterator> it(db->NewIterator(leveldb::ReadOptions()));
        it->SeekToFirst();

        while (it->Valid())
        {
            std::vector<char> k;
            std::vector<char> v;
            decode(it->key().data(), it->key().size(), &k);
            decode(it->value().data(), it->value().size(), &v);
            std::cout << "\"" << &k[0] << "\" -> \"" << &v[0] << "\"\n";
            it->Next();
        }

        std::cout << std::flush;
        it.reset();
        delete db;
    }
}
<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "xesamlivesearch.h"
#include "xesamsession.h"
#include "xesamsearch.h"
#include <strigi/query.h>
#include "queue/jobqueue.h"
#include <iostream>
#include <stdexcept>
#include <cstdlib>
using namespace std;
using namespace Strigi;

class XesamLiveSearch::Private {
public:
    map<string, XesamSession> sessions;
    map<string, XesamSearch> searches;
    XesamLiveSearch& xesam;
    JobQueue& queue;
    Strigi::IndexManager* const indexManager;

    Private(XesamLiveSearch& x, Strigi::IndexManager* i, JobQueue& q)
        :xesam(x), queue(q), indexManager(i) {}
    ~Private();
};
XesamLiveSearch::Private::~Private() {
}
XesamLiveSearch::XesamLiveSearch(Strigi::IndexManager* i, JobQueue& q)
        :XesamLiveSearchInterface(this), p(new Private(*this, i, q)) {}
XesamLiveSearch::~XesamLiveSearch() {
    delete p;
}
string
XesamLiveSearch::NewSession() {
    ostringstream str;
    str << "strigisession" << random();
    string name(str.str());
    if (mkstemp((char*)name.c_str()) == -1) {
        return name; // TODO add error handling
    }
    XesamSession session(*this);
    p->sessions.insert(make_pair(name, session));
    return name;
}
Strigi::Variant
XesamLiveSearch::SetProperty(const std::string& session,
        const std::string& prop, const Strigi::Variant& v) {
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.setProperty(prop, v);
}
Strigi::Variant
XesamLiveSearch::GetProperty(const std::string& session,
        const std::string& prop) {
    Strigi::Variant out;
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.getProperty(prop);
}
void
XesamLiveSearch::CloseSession(const string& session) {
    map<string, XesamSession>::const_iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    p->sessions.erase(i->first);
}
string
XesamLiveSearch::NewSearch(const string& session, const string& query_xml) {
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.newSearch(query_xml);
}
void
XesamLiveSearch::StartSearch(const string& search) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i == p->searches.end()) {
        throw runtime_error("Search is not registered");
    }
    i->second.startSearch();
}
void
XesamLiveSearch::GetHitCount(void* msg, const string& search) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHitCount(msg);
    } else {
        GetHitCountResponse(msg, "Search is not registered.", 0);
    }
    //HitsAdded(search, 10);
}
void
XesamLiveSearch::GetHitCountResponse(void* msg, const char* err, uint32_t count) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitCountResponse(msg, err, count);
    }
}
void
XesamLiveSearch::GetHits(void*msg, const string& search, uint32_t num) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHits(msg, num);
    } else {
        vector<vector<Strigi::Variant> > v;
        GetHitsResponse(msg, "Search is not registered.", v);
    }
}
void
XesamLiveSearch::GetHitsResponse(void* msg, const char* err,
        const vector<vector<Strigi::Variant> >& h) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitsResponse(msg, err, h);
    }
}
void
XesamLiveSearch::GetHitData(void* msg, const string& search,
        const vector<uint32_t>& hit_ids, const vector<string>& properties) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHitData(msg, hit_ids, properties);
    } else {
        vector<vector<Strigi::Variant> > v;
        GetHitDataResponse(msg, "Search is not registered.", v);
    }
}
void
XesamLiveSearch::GetHitDataResponse(void* msg, const char* err,
        const vector<vector<Strigi::Variant> >& v) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitDataResponse(msg, err, v);
    }
}
void
XesamLiveSearch::CloseSearch(const string& search) {
    map<string, XesamSearch>::const_iterator i = p->searches.find(search);
    if (i == p->searches.end()) {
        throw runtime_error("Search is not valid");
    }
    i->second.session().closeSearch(i->second);
}
vector<string>
XesamLiveSearch::GetState() {
    vector<string> state;
    // TODO get the real state
    state.push_back("IDLE");
    return state;
}
void
XesamLiveSearch::HitsAdded(const std::string& search, const uint32_t count) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsAdded(search, count);
    }
}
void
XesamLiveSearch::HitsRemoved(const std::string& search,
        const std::vector<uint32_t>& hit_ids) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsRemoved(search, hit_ids);
    }
}
void
XesamLiveSearch::HitsModified(const std::string& search,
        const std::vector<uint32_t>& hit_ids) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsModified(search, hit_ids);
    }
}
void
XesamLiveSearch::SearchDone(const std::string& search) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->SearchDone(search);
    }
}
void
XesamLiveSearch::StateChanged(const std::vector<std::string>& state_info) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->StateChanged(state_info);
    }
}
void
XesamLiveSearch::addSearch(const std::string& name, XesamSearch& search) {
    p->searches.insert(make_pair(name, search));
}
void
XesamLiveSearch::removeSearch(const std::string& name) {
    p->searches.erase(name);
}
Strigi::IndexManager*
XesamLiveSearch::indexManager() const {
    return p->indexManager;
}
JobQueue&
XesamLiveSearch::queue() const {
    return p->queue;
}
<commit_msg>Do not call mkstemp here, it makes no sense and always returns a failure, because it expects the passed template to end on 'XXXXXX'<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "xesamlivesearch.h"
#include "xesamsession.h"
#include "xesamsearch.h"
#include <strigi/query.h>
#include "queue/jobqueue.h"
#include <iostream>
#include <stdexcept>
#include <cstdlib>
using namespace std;
using namespace Strigi;

class XesamLiveSearch::Private {
public:
    map<string, XesamSession> sessions;
    map<string, XesamSearch> searches;
    XesamLiveSearch& xesam;
    JobQueue& queue;
    Strigi::IndexManager* const indexManager;

    Private(XesamLiveSearch& x, Strigi::IndexManager* i, JobQueue& q)
        :xesam(x), queue(q), indexManager(i) {}
    ~Private();
};
XesamLiveSearch::Private::~Private() {
}
XesamLiveSearch::XesamLiveSearch(Strigi::IndexManager* i, JobQueue& q)
        :XesamLiveSearchInterface(this), p(new Private(*this, i, q)) {}
XesamLiveSearch::~XesamLiveSearch() {
    delete p;
}
string
XesamLiveSearch::NewSession() {
    ostringstream str;
    str << "strigisession" << random();
    string name(str.str());
    XesamSession session(*this);
    p->sessions.insert(make_pair(name, session));
    return name;
}
Strigi::Variant
XesamLiveSearch::SetProperty(const std::string& session,
        const std::string& prop, const Strigi::Variant& v) {
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.setProperty(prop, v);
}
Strigi::Variant
XesamLiveSearch::GetProperty(const std::string& session,
        const std::string& prop) {
    Strigi::Variant out;
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.getProperty(prop);
}
void
XesamLiveSearch::CloseSession(const string& session) {
    map<string, XesamSession>::const_iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    p->sessions.erase(i->first);
}
string
XesamLiveSearch::NewSearch(const string& session, const string& query_xml) {
    map<string, XesamSession>::iterator i = p->sessions.find(session);
    if (i == p->sessions.end()) {
        throw runtime_error("Session is not valid");
    }
    return i->second.newSearch(query_xml);
}
void
XesamLiveSearch::StartSearch(const string& search) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i == p->searches.end()) {
        throw runtime_error("Search is not registered");
    }
    i->second.startSearch();
}
void
XesamLiveSearch::GetHitCount(void* msg, const string& search) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHitCount(msg);
    } else {
        GetHitCountResponse(msg, "Search is not registered.", 0);
    }
    //HitsAdded(search, 10);
}
void
XesamLiveSearch::GetHitCountResponse(void* msg, const char* err, uint32_t count) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitCountResponse(msg, err, count);
    }
}
void
XesamLiveSearch::GetHits(void*msg, const string& search, uint32_t num) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHits(msg, num);
    } else {
        vector<vector<Strigi::Variant> > v;
        GetHitsResponse(msg, "Search is not registered.", v);
    }
}
void
XesamLiveSearch::GetHitsResponse(void* msg, const char* err,
        const vector<vector<Strigi::Variant> >& h) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitsResponse(msg, err, h);
    }
}
void
XesamLiveSearch::GetHitData(void* msg, const string& search,
        const vector<uint32_t>& hit_ids, const vector<string>& properties) {
    map<string, XesamSearch>::iterator i = p->searches.find(search);
    if (i != p->searches.end()) {
        i->second.getHitData(msg, hit_ids, properties);
    } else {
        vector<vector<Strigi::Variant> > v;
        GetHitDataResponse(msg, "Search is not registered.", v);
    }
}
void
XesamLiveSearch::GetHitDataResponse(void* msg, const char* err,
        const vector<vector<Strigi::Variant> >& v) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->GetHitDataResponse(msg, err, v);
    }
}
void
XesamLiveSearch::CloseSearch(const string& search) {
    map<string, XesamSearch>::const_iterator i = p->searches.find(search);
    if (i == p->searches.end()) {
        throw runtime_error("Search is not valid");
    }
    i->second.session().closeSearch(i->second);
}
vector<string>
XesamLiveSearch::GetState() {
    vector<string> state;
    // TODO get the real state
    state.push_back("IDLE");
    return state;
}
void
XesamLiveSearch::HitsAdded(const std::string& search, const uint32_t count) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsAdded(search, count);
    }
}
void
XesamLiveSearch::HitsRemoved(const std::string& search,
        const std::vector<uint32_t>& hit_ids) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsRemoved(search, hit_ids);
    }
}
void
XesamLiveSearch::HitsModified(const std::string& search,
        const std::vector<uint32_t>& hit_ids) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->HitsModified(search, hit_ids);
    }
}
void
XesamLiveSearch::SearchDone(const std::string& search) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->SearchDone(search);
    }
}
void
XesamLiveSearch::StateChanged(const std::vector<std::string>& state_info) {
    for (vector<XesamLiveSearchInterface*>::const_iterator i = ifaces.begin();
            i != ifaces.end(); ++i) {
        (*i)->StateChanged(state_info);
    }
}
void
XesamLiveSearch::addSearch(const std::string& name, XesamSearch& search) {
    p->searches.insert(make_pair(name, search));
}
void
XesamLiveSearch::removeSearch(const std::string& name) {
    p->searches.erase(name);
}
Strigi::IndexManager*
XesamLiveSearch::indexManager() const {
    return p->indexManager;
}
JobQueue&
XesamLiveSearch::queue() const {
    return p->queue;
}
<|endoftext|>


<commit_before>#include <node.h>
#include "include/cef_base.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "includes/cef_handler.h"
#include "includes/cef_sync_handler.h"
#include "appjs_window.h"

using namespace v8;
using namespace appjs;

ClientHandler::ClientHandler()
  : m_MainHwnd(NULL),
    m_BrowserHwnd(NULL) {
}

ClientHandler::~ClientHandler() {
}

Handle<Object> ClientHandler::GetV8WindowHandle(CefRefPtr<CefBrowser> browser) {
  return ClientHandler::GetWindow(browser)->GetV8Handle();
}

Handle<Object> ClientHandler::CreatedBrowser(CefRefPtr<CefBrowser> browser) {
  NativeWindow* window = ClientHandler::GetWindow(browser);
  window->SetBrowser(browser);
  return window->GetV8Handle();
}

void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  AutoLock lock_scope(this);

  if (!browser->IsPopup()) {
    // Set main browser of the application
    if (!m_Browser.get()) {
      m_Browser = browser;
      m_BrowserHwnd = browser->GetWindowHandle();
    }

    Handle<Object> handle = ClientHandler::CreatedBrowser(browser);
    Handle<Value> argv[1] = {String::New("create")};
    node::MakeCallback(handle,"emit", 1, argv);
  }
}

void ClientHandler::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) {
  REQUIRE_UI_THREAD();
  if (!browser->IsPopup()) {
    context->Enter();
    CefRefPtr<CefV8Value> appjsObj = CefV8Value::CreateObject(NULL);
    CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("send", new AppjsSyncHandler(browser));
    context->GetGlobal()->SetValue("appjs", appjsObj, V8_PROPERTY_ATTRIBUTE_NONE);
    appjsObj->SetValue("send", func, V8_PROPERTY_ATTRIBUTE_NONE);
    context->Exit();
  }
}

bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  if (m_BrowserHwnd == browser->GetWindowHandle()) {
    // Since the main window contains the browser window, we need to close
    // the parent window instead of the browser window.
    m_Browser = NULL;
    CloseMainWindow();

    // Return true here so that we can skip closing the browser window
    // in this pass. (It will be destroyed due to the call to close
    // the parent above.)
  }

  // A popup browser window is not contained in another window, so we can let
  // these windows close by themselves.
  return false;
}

void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

// There is a bug in CEF for Linux I think that there is no window object
// when the code reaches here.
#ifndef __LINUX__
  Handle<Object> handle = ClientHandler::GetV8WindowHandle(browser);
  Handle<Value> argv[1] = {String::New("close")};
  node::MakeCallback(handle,"emit",1,argv);
#endif

  if (m_BrowserHwnd == browser->GetWindowHandle()) {

    Local<Object> global = Context::GetCurrent()->Global();
    Local<Object> process = global->Get(String::NewSymbol("process"))->ToObject();
    Local<Object> emitter = Local<Object>::Cast(process->Get(String::NewSymbol("AppjsEmitter")));

    const int argc = 1;
    Handle<Value> argv[1] = {String::New("exit")};
    node::MakeCallback(emitter,"emit",argc,argv);

    DoClose(browser);
  }

#ifndef __LINUX__
  if (!browser->IsPopup()) {
    delete ClientHandler::GetWindow(browser);
  }
#endif
}

void ClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
                         CefRefPtr<CefFrame> frame,
                         int httpStatusCode)
{
  REQUIRE_UI_THREAD();

  if (!browser->IsPopup()) {
    const int argc = 1;
    Handle<Object> handle = ClientHandler::GetV8WindowHandle(browser);
    Handle<Value> argv[argc] = {String::New("ready")};
    node::MakeCallback(handle,"emit",argc,argv);
  }
}

void ClientHandler::SetMainHwnd(CefWindowHandle& hwnd) {
  AutoLock lock_scope(this);

  m_MainHwnd = hwnd;
}
<commit_msg>fixes window closing when popup/dev tools are closed<commit_after>#include <node.h>
#include "include/cef_base.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "includes/cef_handler.h"
#include "includes/cef_sync_handler.h"
#include "appjs_window.h"

using namespace v8;
using namespace appjs;

ClientHandler::ClientHandler()
  : m_MainHwnd(NULL),
    m_BrowserHwnd(NULL) {
}

ClientHandler::~ClientHandler() {
}

Handle<Object> ClientHandler::GetV8WindowHandle(CefRefPtr<CefBrowser> browser) {
  return ClientHandler::GetWindow(browser)->GetV8Handle();
}

Handle<Object> ClientHandler::CreatedBrowser(CefRefPtr<CefBrowser> browser) {
  NativeWindow* window = ClientHandler::GetWindow(browser);
  window->SetBrowser(browser);
  return window->GetV8Handle();
}

void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  AutoLock lock_scope(this);

  if (!browser->IsPopup()) {
    // Set main browser of the application
    if (!m_Browser.get()) {
      m_Browser = browser;
      m_BrowserHwnd = browser->GetWindowHandle();
    }

    Handle<Object> handle = ClientHandler::CreatedBrowser(browser);
    Handle<Value> argv[1] = {String::New("create")};
    node::MakeCallback(handle,"emit", 1, argv);
  }
}

void ClientHandler::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) {
  REQUIRE_UI_THREAD();
  if (!browser->IsPopup()) {
    context->Enter();
    CefRefPtr<CefV8Value> appjsObj = CefV8Value::CreateObject(NULL);
    CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("send", new AppjsSyncHandler(browser));
    context->GetGlobal()->SetValue("appjs", appjsObj, V8_PROPERTY_ATTRIBUTE_NONE);
    appjsObj->SetValue("send", func, V8_PROPERTY_ATTRIBUTE_NONE);
    context->Exit();
  }
}

bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  if (!browser->IsPopup() && m_BrowserHwnd == browser->GetWindowHandle()) {
    // Since the main window contains the browser window, we need to close
    // the parent window instead of the browser window.
    m_Browser = NULL;
    CloseMainWindow();

    // Return true here so that we can skip closing the browser window
    // in this pass. (It will be destroyed due to the call to close
    // the parent above.)
    return true;
  }

  // A popup browser window is not contained in another window, so we can let
  // these windows close by themselves.
  return false;
}

void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  if (!browser->IsPopup()) {
    // There is a bug in CEF for Linux I think that there is no window object
    // when the code reaches here.
#ifndef __LINUX__
    Handle<Object> handle = ClientHandler::GetV8WindowHandle(browser);
    Handle<Value> argv[1] = {String::New("close")};
    node::MakeCallback(handle,"emit",1,argv);
#endif

    if (m_BrowserHwnd == browser->GetWindowHandle()) {
      Local<Object> global = Context::GetCurrent()->Global();
      Local<Object> process = global->Get(String::NewSymbol("process"))->ToObject();
      Local<Object> emitter = Local<Object>::Cast(process->Get(String::NewSymbol("AppjsEmitter")));

      argv[1] = String::New("exit");
      node::MakeCallback(emitter,"emit",1,argv);

      DoClose(browser);
    }

#ifndef __LINUX__
    delete ClientHandler::GetWindow(browser);
#endif
  }
}

void ClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
                         CefRefPtr<CefFrame> frame,
                         int httpStatusCode)
{
  REQUIRE_UI_THREAD();

  if (!browser->IsPopup()) {
    const int argc = 1;
    Handle<Object> handle = ClientHandler::GetV8WindowHandle(browser);
    Handle<Value> argv[argc] = {String::New("ready")};
    node::MakeCallback(handle,"emit",argc,argv);
  }
}

void ClientHandler::SetMainHwnd(CefWindowHandle& hwnd) {
  AutoLock lock_scope(this);

  m_MainHwnd = hwnd;
}
<|endoftext|>


<commit_before>/* Rapicorn
 * Copyright (C) 2007 Tim Janik
 *
 * 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.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_WINDOW_HH__
#define __RAPICORN_WINDOW_HH__

#include <rapicorn/primitives.hh>

namespace Rapicorn {

class Root;
class Window : virtual public Deletable {
  Root         &m_root;
  OwnedMutex   &m_omutex;
  Window&       operator=       (const Window   &window);
protected:
  explicit      Window          (Root           &root,
                                 OwnedMutex     &omutex);
public:
  /* reference ops */
  void          lock            ()      { m_omutex.lock(); }
  bool          trylock         ()      { return m_omutex.trylock(); }
  void          unlock          ()      { m_omutex.unlock(); }
  Root&         root            ();     /* must be locked */
  Root*         peek_root       ();
  /*  window ops */
  bool          visible         ();
  void          show            ();
  void          hide            ();
  bool          closed          ();
  void          close           ();
  /* class */
  /*Con*/       Window          (const Window   &window);
  virtual      ~Window          ();
};

} // Rapicorn

#endif  /* __RAPICORN_WINDOW_HH__ */
<commit_msg>whitespace fixup<commit_after>/* Rapicorn
 * Copyright (C) 2007 Tim Janik
 *
 * 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.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_WINDOW_HH__
#define __RAPICORN_WINDOW_HH__

#include <rapicorn/primitives.hh>

namespace Rapicorn {

class Root;
class Window : virtual public Deletable {
  Root         &m_root;
  OwnedMutex   &m_omutex;
  Window&       operator=       (const Window   &window);
protected:
  explicit      Window          (Root           &root,
                                 OwnedMutex     &omutex);
public:
  /* reference ops */
  void          lock            ()      { m_omutex.lock(); }
  bool          trylock         ()      { return m_omutex.trylock(); }
  void          unlock          ()      { m_omutex.unlock(); }
  Root&         root            ();     /* must be locked */
  Root*         peek_root       ();
  /* window ops */
  bool          visible         ();
  void          show            ();
  void          hide            ();
  bool          closed          ();
  void          close           ();
  /* class */
  /*Con*/       Window          (const Window   &window);
  virtual      ~Window          ();
};

} // Rapicorn

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