<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.
 */

/**
 * \file lower_vec_index_to_cond_assign.cpp
 *
 * Turns indexing into vector types to a series of conditional moves
 * of each channel's swizzle into a temporary.
 *
 * Most GPUs don't have a native way to do this operation, and this
 * works around that.  For drivers using both this pass and
 * ir_vec_index_to_swizzle, there's a risk that this pass will happen
 * before sufficient constant folding to find that the array index is
 * constant.  However, we hope that other optimization passes,
 * particularly constant folding of assignment conditions and copy
 * propagation, will result in the same code in the end.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_optimization.h"
#include "glsl_types.h"

/**
 * Visitor class for replacing expressions with ir_constant values.
 */

class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
public:
   ir_vec_index_to_cond_assign_visitor()
   {
      progress = false;
   }

   ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);

   virtual ir_visitor_status visit_enter(ir_expression *);
   virtual ir_visitor_status visit_enter(ir_swizzle *);
   virtual ir_visitor_status visit_leave(ir_assignment *);
   virtual ir_visitor_status visit_enter(ir_return *);
   virtual ir_visitor_status visit_enter(ir_call *);
   virtual ir_visitor_status visit_enter(ir_if *);

   bool progress;
};

ir_rvalue *
ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
{
   ir_dereference_array *orig_deref = ir->as_dereference_array();
   ir_assignment *assign;
   ir_variable *index, *var;
   ir_dereference *deref;
   ir_expression *condition;
   ir_swizzle *swizzle;
   int i;

   if (!orig_deref)
      return ir;

   if (orig_deref->array->type->is_matrix() ||
       orig_deref->array->type->is_array())
      return ir;

   void *mem_ctx = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(base_ir) ir_variable(glsl_type::int_type,
				    "vec_index_tmp_i",
				    ir_var_temporary);
   base_ir->insert_before(index);
   deref = new(base_ir) ir_dereference_variable(index);
   assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
   base_ir->insert_before(assign);

   /* Temporary where we store whichever value we swizzle out. */
   var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
				  ir_var_temporary);
   base_ir->insert_before(var);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
      deref = new(base_ir) ir_dereference_variable(index);
      condition = new(base_ir) ir_expression(ir_binop_equal,
					     glsl_type::bool_type,
					     deref,
					     new(base_ir) ir_constant(i));

      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
					i, 0, 0, 0, 1);

      deref = new(base_ir) ir_dereference_variable(var);
      assign = new(base_ir) ir_assignment(deref, swizzle, condition);
      base_ir->insert_before(assign);
   }

   this->progress = true;
   return new(base_ir) ir_dereference_variable(var);
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
{
   unsigned int i;

   for (i = 0; i < ir->get_num_operands(); i++) {
      ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
{
   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
    * the result of indexing a vector is.  But maybe at some point we'll end up
    * using swizzling of scalars for vector construction.
    */
   ir->val = convert_vec_index_to_cond_assign(ir->val);

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
{
   ir_variable *index, *var;
   ir_dereference_variable *deref;
   ir_assignment *assign;
   int i;

   ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
   if (ir->condition)
      ir->condition = convert_vec_index_to_cond_assign(ir->condition);

   /* Last, handle the LHS */
   ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();

   if (!orig_deref ||
       orig_deref->array->type->is_matrix() ||
       orig_deref->array->type->is_array())
      return visit_continue;

   void *mem_ctx = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   exec_list list;

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
			       ir_var_temporary);
   list.push_tail(index);
   deref = new(ir) ir_dereference_variable(index);
   assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
   list.push_tail(assign);

   /* Store the RHS to a temporary to avoid reusing its tree. */
   var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
			     ir_var_temporary);
   list.push_tail(var);
   deref = new(ir) ir_dereference_variable(var);
   assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
   list.push_tail(assign);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
      ir_rvalue *condition, *swizzle;

      deref = new(ir) ir_dereference_variable(index);
      condition = new(ir) ir_expression(ir_binop_equal,
					glsl_type::bool_type,
					deref,
					new(ir) ir_constant(i));

      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
				   i, 0, 0, 0, 1);

      deref = new(ir) ir_dereference_variable(var);
      assign = new(ir) ir_assignment(swizzle, deref, condition);
      list.push_tail(assign);
   }

   /* If the original assignment has a condition, respect that original
    * condition!  This is acomplished by wrapping the new conditional
    * assignments in an if-statement that uses the original condition.
    */
   if (ir->condition != NULL) {
      /* No need to clone the condition because the IR that it hangs on is
       * going to be removed from the instruction sequence.
       */
      ir_if *if_stmt = new(mem_ctx) ir_if(ir->condition);

      list.move_nodes_to(&if_stmt->then_instructions);
      ir->insert_before(if_stmt);
   } else {
      ir->insert_before(&list);
   }

   ir->remove();

   this->progress = true;

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
{
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();
      ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);

      if (new_param != param) {
	 param->replace_with(new_param);
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
{
   if (ir->value) {
      ir->value = convert_vec_index_to_cond_assign(ir->value);
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
{
   ir->condition = convert_vec_index_to_cond_assign(ir->condition);

   return visit_continue;
}

bool
do_vec_index_to_cond_assign(exec_list *instructions)
{
   ir_vec_index_to_cond_assign_visitor v;

   visit_list_elements(&v, instructions);

   return v.progress;
}
<commit_msg>glsl: Compare vector indices in blocks<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.
 */

/**
 * \file lower_vec_index_to_cond_assign.cpp
 *
 * Turns indexing into vector types to a series of conditional moves
 * of each channel's swizzle into a temporary.
 *
 * Most GPUs don't have a native way to do this operation, and this
 * works around that.  For drivers using both this pass and
 * ir_vec_index_to_swizzle, there's a risk that this pass will happen
 * before sufficient constant folding to find that the array index is
 * constant.  However, we hope that other optimization passes,
 * particularly constant folding of assignment conditions and copy
 * propagation, will result in the same code in the end.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_optimization.h"
#include "glsl_types.h"

/**
 * Visitor class for replacing expressions with ir_constant values.
 */

class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
public:
   ir_vec_index_to_cond_assign_visitor()
   {
      progress = false;
   }

   ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);

   virtual ir_visitor_status visit_enter(ir_expression *);
   virtual ir_visitor_status visit_enter(ir_swizzle *);
   virtual ir_visitor_status visit_leave(ir_assignment *);
   virtual ir_visitor_status visit_enter(ir_return *);
   virtual ir_visitor_status visit_enter(ir_call *);
   virtual ir_visitor_status visit_enter(ir_if *);

   bool progress;
};

ir_rvalue *
ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
{
   ir_dereference_array *orig_deref = ir->as_dereference_array();
   ir_assignment *assign;
   ir_variable *index, *var;
   ir_dereference *deref;
   int i;

   if (!orig_deref)
      return ir;

   if (orig_deref->array->type->is_matrix() ||
       orig_deref->array->type->is_array())
      return ir;

   void *mem_ctx = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   exec_list list;

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(base_ir) ir_variable(glsl_type::int_type,
				    "vec_index_tmp_i",
				    ir_var_temporary);
   list.push_tail(index);
   deref = new(base_ir) ir_dereference_variable(index);
   assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
   list.push_tail(assign);

   /* Temporary where we store whichever value we swizzle out. */
   var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
				  ir_var_temporary);
   list.push_tail(var);

   /* Generate a single comparison condition "mask" for all of the components
    * in the vector.
    */
   ir_rvalue *const cond_deref =
      compare_index_block(&list, index, 0,
			  orig_deref->array->type->vector_elements,
			  mem_ctx);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
      ir_rvalue *condition_swizzle =
	 new(base_ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);

      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      ir_rvalue *swizzle =
	 new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
				 i, 0, 0, 0, 1);

      deref = new(base_ir) ir_dereference_variable(var);
      assign = new(base_ir) ir_assignment(deref, swizzle, condition_swizzle);
      list.push_tail(assign);
   }

   /* Put all of the new instructions in the IR stream before the old
    * instruction.
    */
   base_ir->insert_before(&list);

   this->progress = true;
   return new(base_ir) ir_dereference_variable(var);
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
{
   unsigned int i;

   for (i = 0; i < ir->get_num_operands(); i++) {
      ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
{
   /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
    * the result of indexing a vector is.  But maybe at some point we'll end up
    * using swizzling of scalars for vector construction.
    */
   ir->val = convert_vec_index_to_cond_assign(ir->val);

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
{
   ir_variable *index, *var;
   ir_dereference_variable *deref;
   ir_assignment *assign;
   int i;

   ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
   if (ir->condition)
      ir->condition = convert_vec_index_to_cond_assign(ir->condition);

   /* Last, handle the LHS */
   ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();

   if (!orig_deref ||
       orig_deref->array->type->is_matrix() ||
       orig_deref->array->type->is_array())
      return visit_continue;

   void *mem_ctx = ralloc_parent(ir);

   assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);

   exec_list list;

   /* Store the index to a temporary to avoid reusing its tree. */
   index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
			       ir_var_temporary);
   list.push_tail(index);
   deref = new(ir) ir_dereference_variable(index);
   assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
   list.push_tail(assign);

   /* Store the RHS to a temporary to avoid reusing its tree. */
   var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
			     ir_var_temporary);
   list.push_tail(var);
   deref = new(ir) ir_dereference_variable(var);
   assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
   list.push_tail(assign);

   /* Generate a single comparison condition "mask" for all of the components
    * in the vector.
    */
   ir_rvalue *const cond_deref =
      compare_index_block(&list, index, 0,
			  orig_deref->array->type->vector_elements,
			  mem_ctx);

   /* Generate a conditional move of each vector element to the temp. */
   for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
      ir_rvalue *condition_swizzle =
	 new(ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1);

      /* Just clone the rest of the deref chain when trying to get at the
       * underlying variable.
       */
      ir_rvalue *swizzle =
	 new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
			    i, 0, 0, 0, 1);

      deref = new(ir) ir_dereference_variable(var);
      assign = new(ir) ir_assignment(swizzle, deref, condition_swizzle);
      list.push_tail(assign);
   }

   /* If the original assignment has a condition, respect that original
    * condition!  This is acomplished by wrapping the new conditional
    * assignments in an if-statement that uses the original condition.
    */
   if (ir->condition != NULL) {
      /* No need to clone the condition because the IR that it hangs on is
       * going to be removed from the instruction sequence.
       */
      ir_if *if_stmt = new(mem_ctx) ir_if(ir->condition);

      list.move_nodes_to(&if_stmt->then_instructions);
      ir->insert_before(if_stmt);
   } else {
      ir->insert_before(&list);
   }

   ir->remove();

   this->progress = true;

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
{
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();
      ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);

      if (new_param != param) {
	 param->replace_with(new_param);
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
{
   if (ir->value) {
      ir->value = convert_vec_index_to_cond_assign(ir->value);
   }

   return visit_continue;
}

ir_visitor_status
ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
{
   ir->condition = convert_vec_index_to_cond_assign(ir->condition);

   return visit_continue;
}

bool
do_vec_index_to_cond_assign(exec_list *instructions)
{
   ir_vec_index_to_cond_assign_visitor v;

   visit_list_elements(&v, instructions);

   return v.progress;
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>

#include <json/json.h>

#include "blackhole/record.hpp"

namespace blackhole {

namespace formatter {

namespace aux {

class json_visitor : public boost::static_visitor<> {
    Json::Value& root;
public:
    json_visitor(Json::Value& root) :
        root(root)
    {}

    template<typename T>
    void operator ()(const std::string& name, const T& attribute) {
        root[name] = attribute;
    }

    void operator ()(const std::string& name, long attribute) {
        root[name] = static_cast<int>(attribute);
    }
};

}

class json_t {
public:
    std::string format(const log::record_t& record) const {
        Json::Value root;
        aux::json_visitor visitor(root);
        for(auto it = record.attributes.begin(); it != record.attributes.end(); ++it) {
            boost::variant<std::string> name = it->first;
            const log::attribute_value_t& property = it->second.value;
            boost::apply_visitor(visitor, name, property);
        }

        Json::FastWriter writer;
        return writer.write(root);
    }
};

} // namespace formatter

} // namespace blackhole

//!@todo: Try to implement logstash formatter.
<commit_msg>Fix build on GCC 4.4.<commit_after>#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>

#include <json/json.h>

#include "blackhole/record.hpp"
#include "blackhole/platform.hpp"

namespace blackhole {

namespace formatter {

namespace aux {

class json_visitor : public boost::static_visitor<> {
    Json::Value& root;
public:
    json_visitor(Json::Value& root) :
        root(root)
    {}

    void operator()(const std::string& name, const std::uint32_t attribute) {
        root[name] = Json::UInt(attribute);
    }

    void operator()(const std::string& name, const std::uint64_t attribute) {
        root[name] = Json::UInt64(attribute);
    }

    void operator()(const std::string& name, const std::int32_t attribute) {
        root[name] = Json::Int(attribute);
    }

    void operator()(const std::string& name, const std::int64_t attribute) {
        root[name] = Json::Int64(attribute);
    }

    void operator()(const std::string& name, const std::string& attribute) {
        root[name] = attribute;
    }

    void operator()(const std::string& name, const std::double_t attribute) {
        root[name] = attribute;
    }

#if defined(__clang__)
    void operator()(const std::string& name, const std::time_t attribute) {
        root[name] = Json::UInt64(attribute);
    }
#endif
};

}

class json_t {
public:
    std::string format(const log::record_t& record) const {
        Json::Value root;
        aux::json_visitor visitor(root);
        for(auto it = record.attributes.begin(); it != record.attributes.end(); ++it) {
            boost::variant<std::string> name = it->first;
            const log::attribute_value_t& property = it->second.value;
            boost::apply_visitor(visitor, name, property);
        }

        Json::FastWriter writer;
        return writer.write(root);
    }
};

} // namespace formatter

} // namespace blackhole

//!@todo: Try to implement logstash formatter.
<|endoftext|>


<commit_before><commit_msg>pthread: Remove tests about return value on win32.<commit_after><|endoftext|>


<commit_before>#include "../lib/radiosity.h"
#include "helper.h"
#include <catch.hpp>

namespace {
constexpr float NUM_SAMPLES = 32;
constexpr float TOLERANCE = 0.01f;
}

TEST_CASE("Form factor of two parallel unit squares one unit apart",
          "[form_factor]") {
    // two triangulated parallel unit squares one unit distance apart,
    // cf. [CW93], Figure 4.22., p.96
    auto bottom_left =
        test_triangle({0.5, -0.5, 0}, {0.5, 0.5, 0}, {-0.5, 0.5, 0}, {0, 0, 1},
                      {0, 0, 1}, {0, 0, 1}); // 0
    auto bottom_right =
        test_triangle({0.5, -0.5, 0}, {-0.5, 0.5, 0}, {-0.5, -0.5, 0},
                      {0, 0, 1}, {0, 0, 1}, {0, 0, 1}); // 1
    auto top_left =
        test_triangle({-0.5f, 0.5f, 1}, {0.5, 0.5, 1}, {0.5, -0.5, 1},
                      {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 2
    auto top_right =
        test_triangle({-0.5f, 0.5f, 1}, {0.5, -0.5, 1}, {-0.5, -0.5, 1},
                      {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 3
    KDTree tree({bottom_left, bottom_right, top_left, top_right});

    // compute the form factor F_(bottom,top) = F_01_23 using the form factor
    // algebra
    float F_0_2 = form_factor(tree, 0, 2, NUM_SAMPLES);
    float F_0_3 = form_factor(tree, 0, 3, NUM_SAMPLES);
    float F_1_2 = form_factor(tree, 1, 2, NUM_SAMPLES);
    float F_1_3 = form_factor(tree, 1, 3, NUM_SAMPLES);

    float F_01_2 = (bottom_left.area() * F_0_2 + bottom_right.area() * F_1_2) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_3 = (bottom_left.area() * F_0_3 + bottom_right.area() * F_1_3) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_23 = F_01_2 + F_01_3;

    constexpr float F_EXPECTED = 0.1998; // cf. [CW93], 4.12., p.96
    REQUIRE(F_01_23 == Approx(F_EXPECTED).epsilon(TOLERANCE));

    // symmetry test
    float F_2_0 = form_factor(tree, 2, 0, NUM_SAMPLES);
    float F_2_1 = form_factor(tree, 2, 1, NUM_SAMPLES);
    float F_3_0 = form_factor(tree, 3, 0, NUM_SAMPLES);
    float F_3_1 = form_factor(tree, 3, 1, NUM_SAMPLES);

    float F_23_0 = (top_left.area() * F_2_0 + top_right.area() * F_3_0) /
                   (top_left.area() + top_right.area());
    float F_23_1 = (top_left.area() * F_2_1 + top_right.area() * F_3_1) /
                   (top_left.area() + top_right.area());
    float F_23_01 = F_23_0 + F_23_1;

    REQUIRE(F_23_01 == Approx(F_EXPECTED).epsilon(TOLERANCE));
}

TEST_CASE("Form factor of two parallel unit squares with 90 degree angle",
          "[form_factor]") {
    // two triangulated parallel unit squares one unit distance apart,
    auto bottom_left =
        test_triangle({0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 0.f, 1.f},
                      {0, 1, 0}, {0, 1, 0}, {0, 1, 0}); // 0
    auto bottom_right =
        test_triangle({0.f, 0.f, 1.f}, {1.f, 0.f, 0.f}, {1.f, 1.f, 0},
                      {0, 1, 0}, {0, 1, 0}, {0, 1, 0}); // 1
    auto back_left = test_triangle({0.f, 0.f, 1}, {1.f, 0.f, 1}, {0.0, 1.f, 1},
                                   {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 2
    auto back_right = test_triangle({0.f, 1.f, 1}, {1.f, 0.f, 1}, {1.f, 1.f, 1},
                                    {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 3
    KDTree tree({bottom_left, bottom_right, back_left, back_right});

    // compute the form factor F_(bottom,top) = F_01_23 using the form factor
    // algebra
    float F_0_2 = form_factor(tree, bottom_left, back_left, 2, NUM_SAMPLES);
    float F_0_3 = form_factor(tree, bottom_left, back_right, 3, NUM_SAMPLES);
    float F_1_2 = form_factor(tree, bottom_right, back_left, 2, NUM_SAMPLES);
    float F_1_3 = form_factor(tree, bottom_right, back_right, 3, NUM_SAMPLES);

    float F_01_2 = (bottom_left.area() * F_0_2 + bottom_right.area() * F_1_2) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_3 = (bottom_left.area() * F_0_3 + bottom_right.area() * F_1_3) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_23 = F_01_2 + F_01_3;

    // TODO: Calculate expected value analytically
    constexpr float F_EXPECTED = 0.01188f;
    REQUIRE(F_01_23 == Approx(F_EXPECTED).epsilon(TOLERANCE));

    // symmetry test
    float F_2_0 = form_factor(tree, back_left, bottom_left, 0, NUM_SAMPLES);
    float F_2_1 = form_factor(tree, back_left, bottom_right, 1, NUM_SAMPLES);
    float F_3_0 = form_factor(tree, back_right, bottom_left, 0, NUM_SAMPLES);
    float F_3_1 = form_factor(tree, back_right, bottom_right, 1, NUM_SAMPLES);

    float F_23_0 = (back_left.area() * F_2_0 + back_right.area() * F_3_0) /
                   (back_left.area() + back_right.area());
    float F_23_1 = (back_left.area() * F_2_1 + back_right.area() * F_3_1) /
                   (back_left.area() + back_right.area());
    float F_23_01 = F_23_0 + F_23_1;

    REQUIRE(F_23_01 == Approx(F_EXPECTED).epsilon(TOLERANCE));
}
<commit_msg>Fix orthogonal form factor test value and increase tolerance.<commit_after>#include "../lib/radiosity.h"
#include "helper.h"
#include <catch.hpp>

namespace {
constexpr float NUM_SAMPLES = 32;
constexpr float TOLERANCE = 0.1f;
}

TEST_CASE("Form factor of two parallel unit squares one unit apart",
          "[form_factor]") {
    // two triangulated parallel unit squares one unit distance apart,
    // cf. [CW93], Figure 4.22., p.96
    auto bottom_left =
        test_triangle({0.5, -0.5, 0}, {0.5, 0.5, 0}, {-0.5, 0.5, 0}, {0, 0, 1},
                      {0, 0, 1}, {0, 0, 1}); // 0
    auto bottom_right =
        test_triangle({0.5, -0.5, 0}, {-0.5, 0.5, 0}, {-0.5, -0.5, 0},
                      {0, 0, 1}, {0, 0, 1}, {0, 0, 1}); // 1
    auto top_left =
        test_triangle({-0.5f, 0.5f, 1}, {0.5, 0.5, 1}, {0.5, -0.5, 1},
                      {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 2
    auto top_right =
        test_triangle({-0.5f, 0.5f, 1}, {0.5, -0.5, 1}, {-0.5, -0.5, 1},
                      {0, 0, -1}, {0, 0, -1}, {0, 0, -1}); // 3
    KDTree tree({bottom_left, bottom_right, top_left, top_right});

    // compute the form factor F_(bottom,top) = F_01_23 using the form factor
    // algebra
    float F_0_2 = form_factor(tree, 0, 2, NUM_SAMPLES);
    float F_0_3 = form_factor(tree, 0, 3, NUM_SAMPLES);
    float F_1_2 = form_factor(tree, 1, 2, NUM_SAMPLES);
    float F_1_3 = form_factor(tree, 1, 3, NUM_SAMPLES);

    float F_01_2 = (bottom_left.area() * F_0_2 + bottom_right.area() * F_1_2) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_3 = (bottom_left.area() * F_0_3 + bottom_right.area() * F_1_3) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_23 = F_01_2 + F_01_3;

    constexpr float F_EXPECTED = 0.1998; // cf. [CW93], 4.12., p.96
    REQUIRE(F_01_23 == Approx(F_EXPECTED).epsilon(TOLERANCE));

    // symmetry test
    float F_2_0 = form_factor(tree, 2, 0, NUM_SAMPLES);
    float F_2_1 = form_factor(tree, 2, 1, NUM_SAMPLES);
    float F_3_0 = form_factor(tree, 3, 0, NUM_SAMPLES);
    float F_3_1 = form_factor(tree, 3, 1, NUM_SAMPLES);

    float F_23_0 = (top_left.area() * F_2_0 + top_right.area() * F_3_0) /
                   (top_left.area() + top_right.area());
    float F_23_1 = (top_left.area() * F_2_1 + top_right.area() * F_3_1) /
                   (top_left.area() + top_right.area());
    float F_23_01 = F_23_0 + F_23_1;

    REQUIRE(F_23_01 == Approx(F_EXPECTED).epsilon(TOLERANCE));
}

TEST_CASE("Form factor of two orthogonal unit squares with 90 degree angle",
          "[form_factor]") {
    auto bottom_left = test_triangle({0, 0, 0}, {1, 0, 1}, {1, 0, 0}, {0, 1, 0},
                                     {0, 1, 0}, {0, 1, 0}); // 0
    auto bottom_right = test_triangle({0, 0, 0}, {0, 0, 1}, {1, 0, 1},
                                      {0, 1, 0}, {0, 1, 0}, {0, 1, 0}); // 1
    auto back_left = test_triangle({0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 0, 1},
                                   {0, 0, 1}, {0, 0, 1}); // 2
    auto back_right = test_triangle({0, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 1},
                                    {0, 0, 1}, {0, 0, 1}); // 3
    KDTree tree({bottom_left, bottom_right, back_left, back_right});

    // compute the form factor F_(bottom,top) = F_01_23 using the form factor
    // algebra
    float F_0_2 = form_factor(tree, bottom_left, back_left, 2, NUM_SAMPLES);
    float F_0_3 = form_factor(tree, bottom_left, back_right, 3, NUM_SAMPLES);
    float F_1_2 = form_factor(tree, bottom_right, back_left, 2, NUM_SAMPLES);
    float F_1_3 = form_factor(tree, bottom_right, back_right, 3, NUM_SAMPLES);

    float F_01_2 = (bottom_left.area() * F_0_2 + bottom_right.area() * F_1_2) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_3 = (bottom_left.area() * F_0_3 + bottom_right.area() * F_1_3) /
                   (bottom_left.area() + bottom_right.area());
    float F_01_23 = F_01_2 + F_01_3;

    // TODO: Calculate expected value analytically
    constexpr float F_EXPECTED = 0.2;
    REQUIRE(F_01_23 == Approx(F_EXPECTED).epsilon(TOLERANCE));

    // symmetry test
    float F_2_0 = form_factor(tree, back_left, bottom_left, 0, NUM_SAMPLES);
    float F_2_1 = form_factor(tree, back_left, bottom_right, 1, NUM_SAMPLES);
    float F_3_0 = form_factor(tree, back_right, bottom_left, 0, NUM_SAMPLES);
    float F_3_1 = form_factor(tree, back_right, bottom_right, 1, NUM_SAMPLES);

    float F_23_0 = (back_left.area() * F_2_0 + back_right.area() * F_3_0) /
                   (back_left.area() + back_right.area());
    float F_23_1 = (back_left.area() * F_2_1 + back_right.area() * F_3_1) /
                   (back_left.area() + back_right.area());
    float F_23_01 = F_23_0 + F_23_1;

    REQUIRE(F_23_01 == Approx(F_EXPECTED).epsilon(TOLERANCE));
}
<|endoftext|>


<commit_before>/*!
 * \file gl_flex.fl.cpp
 * \brief file gl_flex.fl.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

/*!
 * \file gl_flex.fl.cpp
 * \brief file gl_flex.fl.cpp
 *
 * Copyright 2013 by Nomovok Ltd.
 *
 * Contact: info@nomovok.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 *
 */

%option noyywrap

%{
#include "HeaderCreator.hpp"

%}
/* definitions */
space [ \t]+
allSpace [ \t\n]
anychar .|{allSpace}
const "const"{allSpace}+
GLTYPEARB GLchar|GLcharARB|GLintptr|GLintpreARB|GLsizeiptr|GLsizeiptrARB|GLhandleARB|GLhalfARB|GLhalfNV
GLTYPESIMPLE GLenum|GLbitfield|GLboolean|GLsizei|GLvoid|GLuint64EXT|GLuint64|GLint64|GLint64EXT
GLTYPEBYTE GLbyte|GLubyte
GLTYPESHORT GLshort|GLushort
GLTYPEINT GLint|GLuint|int
GLTYPEFLOAT GLfloat|GLdouble|GLclampf|GLclampd|float|double
GLTYE {GLTYPEARB}|{GLTYPESIMPLE}|{GLTYPEBYTE}|{GLTYPESHORT}|{GLTYPEINT}|{GLTYPEFLOAT}|void|wchar_t
GLPTR {GLTYE}{allSpace}*"*"
GLTYPE {GLTYE}|{GLPTR}
CGLTYPE {const}{GLTYPE}
CGLGLTYPE {CGLTYPE}|{GLTYPE}|GLDEBUGPROC|GLDEBUGPROCARB|GLVULKANPROCNV

EGLPLATFORMTYPE EGLint|EGLNativeDisplayType|EGLNativePixmapType|EGLNativeWindowType
EGLBASETYPE void|EGLBoolean|EGLDisplay|EGLConfig|EGLSurface|EGLContext|EGLenum|EGLClientBuffer|EGLSync|EGLAttrib|EGLTime|EGLImage
EGLKHRTYPE EGLSyncKHR|EGLAttribKHR|EGLLabelKHR|EGLObjectKHR|EGLTimeKHR|EGLImageKHR|EGLStreamKHR|EGLuint64KHR|EGLNativeFileDescriptorKHR
EGLANDTYPE EGLsizeiANDROID|EGLSetBlobFuncANDROID|EGLsizeiANDROID|EGLnsecsANDROID
EGLEXTTYPE EGLDeviceEXT|EGLOutputLayerEXT|EGLOutputPortEXT|EGLSyncNV|EGLTimeNV|EGLuint64NV|struct{space}EGLClientPixmapHI
EGLTYP {EGLPLATFORMTYPE}|{EGLBASETYPE}|{EGLKHRTYPE}|{EGLANDTYPE}|{EGLEXTTYPE}

EGLPTR {EGLTYP}{allSpace}*"*"
EGLTYPE {EGLTYP}|{EGLPTR}
CEGLTYPE {const}{EGLTYPE}
CEGLEGLTYPE {EGLTYPE}|{CEGLTYPE}

%%

%{
 /*rules*/
%}

GLAPI{space}+{CGLGLTYPE}{space}*+APIENTRY{space}+gl[^\n]*\n  {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext, "GLAPI", "APIENTRY");
  openGL_function_info::openGL_functionList().push_back(ptr);
}

GL_APICALL{space}+{CGLGLTYPE}{space}*+GL_APIENTRY{space}+gl[^\n]*\n  {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext,"GL_APICALL", "GL_APIENTRY");
  openGL_function_info::openGL_functionList().push_back(ptr);
}

EGLAPI{space}+{CEGLEGLTYPE}{space}*+EGLAPIENTRY{space}+egl[^\n]*\n {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext,"EGLAPI", "EGLAPIENTRY", "egl");
  /* disclude if function name is eglGetProcAddress */
  if (ptr->function_name() != "eglGetProcAddress")
    {
      openGL_function_info::openGL_functionList().push_back(ptr);
    }
  else
    {
      delete ptr;
    }
}

FUNCTIONPOINTERMODE {
  openGL_function_info::use_function_pointer_mode()=use_function_pointer;
}

NOFUNCTIONPOINTERMODE_PTR_TYPE_DECLARED {
  openGL_function_info::use_function_pointer_mode()=dont_use_function_pointer_type_declared;
}

NOFUNCTIONPOINTERMODE_PTR_TYPE_NOTDECLARED {
  openGL_function_info::use_function_pointer_mode()=dont_use_function_pointer_type_undeclared;
}

[ \t\n]+  { /* do nothing */  }
. { /* do nothing */  }
%%

/*code*/

int main(int argc, char **argv)
{
  //read input from stdin!
  //arguments affect behavior.

  string headerName, sourceName, current;
  string macroPrefix(""), function_prefix(""), namespaceName;
  string path, output_cpp("kgl.cpp"), output_hpp("kgl.hpp");
  ofstream sourceFile, headerFile;
  list<string> fileNames;
  int num;
  map<string,openGL_function_info*>::iterator gg;

  for(int i=1;i<argc;++i)
    {
      string::iterator iter;

      current=argv[i];
      iter=find(current.begin(), current.end(), '=');
      if (iter!=current.end() && iter+1!=current.end())
        {
          if (string(current.begin(),iter)==string("macro_prefix"))
            {
              macroPrefix=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("function_prefix"))
            {
              function_prefix=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("namespace"))
            {
              namespaceName=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("path"))
            {
              path=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("output_cpp"))
            {
              output_cpp=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("output_hpp"))
            {
              output_hpp=string(iter+1,current.end());
            }
        }
      else //not a command parameter, then is a file.
        {
          fileNames.push_back(current);
        }
    }

  headerName=output_hpp;
  sourceName=output_cpp;

  sourceFile.open(sourceName.c_str());
  headerFile.open(headerName.c_str());
  if (!sourceFile || !headerFile)
    {
      cerr << "Failed to open one file for writing!\n";
      exit(-1);
    }

  openGL_function_info::SetMacroPrefix(macroPrefix);
  openGL_function_info::SetFunctionPrefix(function_prefix);
  openGL_function_info::SetNamespace(namespaceName);

  //read from stdin the function prototypes
  YY_FLUSH_BUFFER;
  yyrestart(stdin);
  yylex();

  openGL_function_info::HeaderStart(headerFile, fileNames);
  openGL_function_info::SourceStart(sourceFile, fileNames);

  for(num=0,gg=openGL_function_info::lookUp().begin(); gg!=openGL_function_info::lookUp().end(); ++gg, ++num)
    {

      gg->second->output_to_header(headerFile);
      gg->second->output_to_source(sourceFile);

      //gg->second->GetInfo(std::cout);
      //std::cout << gg->second->function_name() << "\n";

    }

  openGL_function_info::HeaderEnd(headerFile, fileNames);
  openGL_function_info::SourceEnd(sourceFile, fileNames);

  //  cout << "\nGL functions counted=" << openGL_function_info::numberFunctions()
  //   << "\n";

}
<commit_msg>gl_generator/gl_flex: fix building with MSVC<commit_after>/*!
 * \file gl_flex.fl.cpp
 * \brief file gl_flex.fl.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

/*!
 * \file gl_flex.fl.cpp
 * \brief file gl_flex.fl.cpp
 *
 * Copyright 2013 by Nomovok Ltd.
 *
 * Contact: info@nomovok.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 *
 */

%option noyywrap

%{
#include "HeaderCreator.hpp"
#ifdef _MSC_VER
#include <io.h>
#define isatty(x) _isatty(x)
#define YY_NO_UNISTD_H
#endif

%}
/* definitions */
space [ \t]+
allSpace [ \t\n]
anychar .|{allSpace}
const "const"{allSpace}+
GLTYPEARB GLchar|GLcharARB|GLintptr|GLintpreARB|GLsizeiptr|GLsizeiptrARB|GLhandleARB|GLhalfARB|GLhalfNV
GLTYPESIMPLE GLenum|GLbitfield|GLboolean|GLsizei|GLvoid|GLuint64EXT|GLuint64|GLint64|GLint64EXT
GLTYPEBYTE GLbyte|GLubyte
GLTYPESHORT GLshort|GLushort
GLTYPEINT GLint|GLuint|int
GLTYPEFLOAT GLfloat|GLdouble|GLclampf|GLclampd|float|double
GLTYE {GLTYPEARB}|{GLTYPESIMPLE}|{GLTYPEBYTE}|{GLTYPESHORT}|{GLTYPEINT}|{GLTYPEFLOAT}|void|wchar_t
GLPTR {GLTYE}{allSpace}*"*"
GLTYPE {GLTYE}|{GLPTR}
CGLTYPE {const}{GLTYPE}
CGLGLTYPE {CGLTYPE}|{GLTYPE}|GLDEBUGPROC|GLDEBUGPROCARB|GLVULKANPROCNV

EGLPLATFORMTYPE EGLint|EGLNativeDisplayType|EGLNativePixmapType|EGLNativeWindowType
EGLBASETYPE void|EGLBoolean|EGLDisplay|EGLConfig|EGLSurface|EGLContext|EGLenum|EGLClientBuffer|EGLSync|EGLAttrib|EGLTime|EGLImage
EGLKHRTYPE EGLSyncKHR|EGLAttribKHR|EGLLabelKHR|EGLObjectKHR|EGLTimeKHR|EGLImageKHR|EGLStreamKHR|EGLuint64KHR|EGLNativeFileDescriptorKHR
EGLANDTYPE EGLsizeiANDROID|EGLSetBlobFuncANDROID|EGLsizeiANDROID|EGLnsecsANDROID
EGLEXTTYPE EGLDeviceEXT|EGLOutputLayerEXT|EGLOutputPortEXT|EGLSyncNV|EGLTimeNV|EGLuint64NV|struct{space}EGLClientPixmapHI
EGLTYP {EGLPLATFORMTYPE}|{EGLBASETYPE}|{EGLKHRTYPE}|{EGLANDTYPE}|{EGLEXTTYPE}

EGLPTR {EGLTYP}{allSpace}*"*"
EGLTYPE {EGLTYP}|{EGLPTR}
CEGLTYPE {const}{EGLTYPE}
CEGLEGLTYPE {EGLTYPE}|{CEGLTYPE}

%%

%{
 /*rules*/
%}

GLAPI{space}+{CGLGLTYPE}{space}*+APIENTRY{space}+gl[^\n]*\n  {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext, "GLAPI", "APIENTRY");
  openGL_function_info::openGL_functionList().push_back(ptr);
}

GL_APICALL{space}+{CGLGLTYPE}{space}*+GL_APIENTRY{space}+gl[^\n]*\n  {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext,"GL_APICALL", "GL_APIENTRY");
  openGL_function_info::openGL_functionList().push_back(ptr);
}

EGLAPI{space}+{CEGLEGLTYPE}{space}*+EGLAPIENTRY{space}+egl[^\n]*\n {
  openGL_function_info *ptr;
  ptr=new openGL_function_info(yytext,"EGLAPI", "EGLAPIENTRY", "egl");
  /* disclude if function name is eglGetProcAddress */
  if (ptr->function_name() != "eglGetProcAddress")
    {
      openGL_function_info::openGL_functionList().push_back(ptr);
    }
  else
    {
      delete ptr;
    }
}

FUNCTIONPOINTERMODE {
  openGL_function_info::use_function_pointer_mode()=use_function_pointer;
}

NOFUNCTIONPOINTERMODE_PTR_TYPE_DECLARED {
  openGL_function_info::use_function_pointer_mode()=dont_use_function_pointer_type_declared;
}

NOFUNCTIONPOINTERMODE_PTR_TYPE_NOTDECLARED {
  openGL_function_info::use_function_pointer_mode()=dont_use_function_pointer_type_undeclared;
}

[ \t\n]+  { /* do nothing */  }
. { /* do nothing */  }
%%

/*code*/

int main(int argc, char **argv)
{
  //read input from stdin!
  //arguments affect behavior.

  string headerName, sourceName, current;
  string macroPrefix(""), function_prefix(""), namespaceName;
  string path, output_cpp("kgl.cpp"), output_hpp("kgl.hpp");
  ofstream sourceFile, headerFile;
  list<string> fileNames;
  int num;
  map<string,openGL_function_info*>::iterator gg;

  for(int i=1;i<argc;++i)
    {
      string::iterator iter;

      current=argv[i];
      iter=find(current.begin(), current.end(), '=');
      if (iter!=current.end() && iter+1!=current.end())
        {
          if (string(current.begin(),iter)==string("macro_prefix"))
            {
              macroPrefix=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("function_prefix"))
            {
              function_prefix=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("namespace"))
            {
              namespaceName=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("path"))
            {
              path=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("output_cpp"))
            {
              output_cpp=string(iter+1,current.end());
            }

          if (string(current.begin(),iter)==string("output_hpp"))
            {
              output_hpp=string(iter+1,current.end());
            }
        }
      else //not a command parameter, then is a file.
        {
          fileNames.push_back(current);
        }
    }

  headerName=output_hpp;
  sourceName=output_cpp;

  sourceFile.open(sourceName.c_str());
  headerFile.open(headerName.c_str());
  if (!sourceFile || !headerFile)
    {
      cerr << "Failed to open one file for writing!\n";
      exit(-1);
    }

  openGL_function_info::SetMacroPrefix(macroPrefix);
  openGL_function_info::SetFunctionPrefix(function_prefix);
  openGL_function_info::SetNamespace(namespaceName);

  //read from stdin the function prototypes
  YY_FLUSH_BUFFER;
  yyrestart(stdin);
  yylex();

  openGL_function_info::HeaderStart(headerFile, fileNames);
  openGL_function_info::SourceStart(sourceFile, fileNames);

  for(num=0,gg=openGL_function_info::lookUp().begin(); gg!=openGL_function_info::lookUp().end(); ++gg, ++num)
    {

      gg->second->output_to_header(headerFile);
      gg->second->output_to_source(sourceFile);

      //gg->second->GetInfo(std::cout);
      //std::cout << gg->second->function_name() << "\n";

    }

  openGL_function_info::HeaderEnd(headerFile, fileNames);
  openGL_function_info::SourceEnd(sourceFile, fileNames);

  //  cout << "\nGL functions counted=" << openGL_function_info::numberFunctions()
  //   << "\n";

}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2018, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file cpu_profile.cxx
 *
 * Helper functions for compiling CPU profiles from running targets.
 *
 * @author Balazs Racz
 * @date 6 June 2018
 */

#ifndef _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_
#define _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_

#include <unwind.h>

#define MAX_STRACE 20
#define TRACE_BUFFER_LENGTH_WORDS 3000 // 12 kbytes

extern "C" {
extern void *stacktrace[MAX_STRACE];
extern int strace_len;
void call_unwind(void);
}

/// A custom unidirectional memory allocator so we can take traces from
/// interrupts.
class TraceAllocator {
public:
    void* alloc(unsigned size) {
        size += 3;
        size /= 4;
        if (endOffset + size > TRACE_BUFFER_LENGTH_WORDS) {
            return nullptr;
        }
        void* ret = buffer + endOffset;
        endOffset += size;
        return ret;
    }

private:
    /// Storage of the trace buffer.
    unsigned buffer[TRACE_BUFFER_LENGTH_WORDS];
    /// index into buffer[] to denote first free element.
    unsigned endOffset{0};
public:
    /// how many times did we run into the MAX_STRACE limit.
    unsigned limitReached{0};
    /// How many times did we apply the backtrace hack to work around
    /// single-entry backtraces.
    unsigned singleLenHack{0};
} allocator;

/// Linked list entry type for a call-stack backtrace.
struct trace
{
    /// For quick comparison of traces.
    unsigned hash : 24;
    /// Number of entries in the trace.
    unsigned len : 8;
    /// Link to the next trace entry.
    struct trace *next;
    /// total memory (bytes) allocated via this trace.
    unsigned total_size;
};

struct trace *all_traces = nullptr;

/// Computes a 24-bit hash code for a stack trace.
/// @param len is the number of entries in the stack trace (each 4 bytes)
/// @param buf is the first element (leaf) of the trace.
/// @return hash code.
unsigned hash_trace(unsigned len, unsigned *buf)
{
    unsigned ret = 0;
    for (unsigned i = 0; i < len; ++i)
    {
        ret *= (1 + 4 + 16);
        ret ^= buf[i];
    }
    return ret & 0xFFFFFF;
}

/// Finds if the current trace exists in the trace map.
/// @param hash is the previously computed hash value for the current trace.
/// @return nullptr if the current trace is not matching anything in the trace
/// buffer, otherwise the storage pointer to the copy of the current trace in
/// the trace buffer.
struct trace *find_current_trace(unsigned hash)
{
    for (struct trace *t = all_traces; t; t = t->next)
    {
        if (t->hash != (hash & 0xFFFFFF))
            continue;
        if (t->len != strace_len)
            continue;
        unsigned *payload = (unsigned *)(t + 1);
        if (memcmp(payload, stacktrace, strace_len * sizeof(stacktrace[0])) !=
            0)
            continue;
        return t;
    }
    return nullptr;
}

/// Adds the current trace to the trace buffer.
/// @param hash is the hash value ofthe current trace.
/// @return pointer to the trace in the trace buffer. The stats of the new
/// entry are not yet updated. Returns nullptr if the trace buffer is full.
struct trace *add_new_trace(unsigned hash)
{
    unsigned total_size = sizeof(struct trace) + strace_len * sizeof(stacktrace[0]);
    struct trace* t = (struct trace*)allocator.alloc(total_size);
    if (!t) return nullptr;
    memcpy(t + 1, stacktrace, strace_len * sizeof(stacktrace[0]));
    t->hash = hash;
    t->len = strace_len;
    t->total_size = 0;
    t->next = all_traces;
    all_traces = t;
    return t;
}

/// Current stacktrace buffer. This will be written from an interrupt.
void *stacktrace[MAX_STRACE];
/// Number of entries in stacktrace.
int strace_len;

/// This struct definition mimics the internal structures of libgcc in
/// arm-none-eabi binary. It's not portable and might break in the future.
struct core_regs
{
  unsigned r[16];
};

/// This struct definition mimics the internal structures of libgcc in
/// arm-none-eabi binary. It's not portable and might break in the future.
typedef struct
{
  unsigned demand_save_flags;
  struct core_regs core;
} phase2_vrs;

/// We store what we know about the external context at interrupt entry in this
/// structure.
phase2_vrs main_context;
/// Saved value of the lr register at the exception entry.
unsigned saved_lr;

/// Takes registers from the core state and the saved exception context and
/// fills in the structure necessary for the LIBGCC unwinder.
void fill_phase2_vrs(volatile unsigned* fault_args) {
    __asm volatile (
        "mov  r0, %0 \n"
        "str  r4, [r0, 4*4] \n"
        "str  r5, [r0, 5*4] \n"
        "str  r6, [r0, 6*4] \n"
        "str  r7, [r0, 7*4] \n"
        "str  r8, [r0, 8*4] \n"
        "str  r9, [r0, 9*4] \n"
        "str  r10, [r0, 10*4] \n"
        "str  r11, [r0, 11*4] \n"
        "str  r12, [r0, 12*4] \n"
        "str  r13, [r0, 13*4] \n"
        "str  r14, [r0, 14*4] \n"
        : : "r"(main_context.core.r)  : "r0"   );
    main_context.demand_save_flags = 0;
    main_context.core.r[0] = fault_args[0];
    main_context.core.r[1] = fault_args[1];
    main_context.core.r[2] = fault_args[2];
    main_context.core.r[3] = fault_args[3];
    main_context.core.r[12] = fault_args[4];
    // We add +2 here because first thing libgcc does with the lr value is
    // subtract two, presuming that lr points to after a branch
    // instruction. However, exception entry's saved PC can point to the first
    // instruction of a function and we don't want to have the backtrace end up
    // showing the previous function.
    main_context.core.r[14] = fault_args[6] + 2;
    main_context.core.r[15] = fault_args[6];
    saved_lr = fault_args[5];
    main_context.core.r[13] = (unsigned)(fault_args + 8); // stack pointer
}
extern "C" {
_Unwind_Reason_Code
__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
                       phase2_vrs * entry_vrs);
}

/// Static variable for trace_func.
void* last_ip;

/// Callback from the unwind backtrace function.
_Unwind_Reason_Code trace_func(struct _Unwind_Context *context, void *arg)
{
    void *ip;
    ip = (void *)_Unwind_GetIP(context);
    if (strace_len == 0)
    {
        //stacktrace[strace_len++] = ip;
        // By taking the beginning of the function for the immediate interrupt
        // we will attempt to coalesce more traces.
        //ip = (void *)_Unwind_GetRegionStart(context);
    }
    else if (last_ip == ip)
    {
        if (strace_len == 1 && saved_lr != _Unwind_GetGR (context, 14)) {
            _Unwind_SetGR (context, 14, saved_lr);
            allocator.singleLenHack++;
            return _URC_NO_REASON;
        }
        return _URC_END_OF_STACK;
    }
    if (strace_len >= MAX_STRACE-1)
    {
        ++allocator.limitReached;
        return _URC_END_OF_STACK;
    }
    //stacktrace[strace_len++] = ip;
    last_ip = ip;
    ip = (void *)_Unwind_GetRegionStart(context);
    stacktrace[strace_len++] = ip;
    return _URC_NO_REASON;
}

/// Called from the interrupt handler to take a CPU trace for the current
/// exception.
void take_cpu_trace()
{
    memset(stacktrace, 0, sizeof(stacktrace));
    strace_len = 0;
    last_ip = nullptr;
    phase2_vrs first_context = main_context;
    __gnu_Unwind_Backtrace(&trace_func, 0, &first_context);
    // This is a workaround for the case when the function in which we had the
    // exception trigger does not have a stack saved LR. In this case the
    // backtrace will fail after the first step. We manually append the second
    // step to have at least some idea of what's going on.
    if (strace_len == 1) {
        main_context.core.r[14] = saved_lr;
        main_context.core.r[15] = saved_lr;
        __gnu_Unwind_Backtrace(&trace_func, 0, &main_context);
    }
    unsigned h = hash_trace(strace_len, (unsigned *)stacktrace);
    struct trace *t = find_current_trace(h);
    if (!t)
    {
        t = add_new_trace(h);
    }
    if (t)
    {
        t->total_size += 1;
    }
}

/// Change this value to runtime disable and enable the CPU profile gathering
/// code.
bool enable_profiling = 0;
volatile unsigned* exception_args;
volatile unsigned is_process;
volatile unsigned saved_sp;

/// Helper function to declare the CPU usage tick interrupt.
/// @param irq_handler_name is the name of the interrupt to declare, for example
/// timer4a_interrupt_handler.
/// @param CLEAR_IRQ_FLAG is a c++ statement or statements in { ... } that will
/// be executed before returning from the interrupt to clear the timer IRQ flag.
#define DEFINE_CPU_PROFILE_INTERRUPT_HANDLER(irq_handler_name, CLEAR_IRQ_FLAG) \
    extern "C"                                                                 \
    {                                                                          \
        void __attribute__((__noinline__)) load_monitor_interrupt_handler(     \
            volatile unsigned *exception_args, unsigned exception_return_code) \
        {                                                                      \
            if (enable_profiling)                                              \
            {                                                                  \
                fill_phase2_vrs(exception_args);                               \
                take_cpu_trace();                                              \
            }                                                                  \
            cpuload_tick(is_process & 4 ? 0 : 255);                            \
            CLEAR_IRQ_FLAG;                                                    \
        }                                                                      \
        void __attribute__((__naked__)) irq_handler_name(void)                 \
        {                                                                      \
            __asm volatile(" tst   lr, #4               \n"                    \
                           " ite   eq                   \n"                    \
                           " mrseq r0, msp              \n"                    \
                           " mrsne r0, psp              \n"                    \
                           " ldr r1, =exception_args \n"                       \
                           " str r0, [r1] \n"                                  \
                           " ldr r1, =is_process \n"                           \
                           " str lr, [r1] \n"                                  \
                           " ldr r0,  =load_monitor_interrupt_handler  \n"     \
                           " bx  r0  \n"                                       \
                           :                                                   \
                           :                                                   \
                           : "r0", "r1");                                      \
        }                                                                      \
    }

#endif // _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_
<commit_msg>Fixes incorrect attribution of exception arguments and core register recordings.<commit_after>/** \copyright
 * Copyright (c) 2018, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file cpu_profile.cxx
 *
 * Helper functions for compiling CPU profiles from running targets.
 *
 * @author Balazs Racz
 * @date 6 June 2018
 */

#ifndef _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_
#define _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_

#include <unwind.h>

#define MAX_STRACE 20
#define TRACE_BUFFER_LENGTH_WORDS 3000 // 12 kbytes

extern "C" {
extern void *stacktrace[MAX_STRACE];
extern int strace_len;
void call_unwind(void);
}

/// A custom unidirectional memory allocator so we can take traces from
/// interrupts.
class TraceAllocator {
public:
    void* alloc(unsigned size) {
        size += 3;
        size /= 4;
        if (endOffset + size > TRACE_BUFFER_LENGTH_WORDS) {
            return nullptr;
        }
        void* ret = buffer + endOffset;
        endOffset += size;
        return ret;
    }

private:
    /// Storage of the trace buffer.
    unsigned buffer[TRACE_BUFFER_LENGTH_WORDS];
    /// index into buffer[] to denote first free element.
    unsigned endOffset{0};
public:
    /// how many times did we run into the MAX_STRACE limit.
    unsigned limitReached{0};
    /// How many times did we apply the backtrace hack to work around
    /// single-entry backtraces.
    unsigned singleLenHack{0};
} allocator;

/// Linked list entry type for a call-stack backtrace.
struct trace
{
    /// For quick comparison of traces.
    unsigned hash : 24;
    /// Number of entries in the trace.
    unsigned len : 8;
    /// Link to the next trace entry.
    struct trace *next;
    /// total memory (bytes) allocated via this trace.
    unsigned total_size;
};

struct trace *all_traces = nullptr;

/// Computes a 24-bit hash code for a stack trace.
/// @param len is the number of entries in the stack trace (each 4 bytes)
/// @param buf is the first element (leaf) of the trace.
/// @return hash code.
unsigned hash_trace(unsigned len, unsigned *buf)
{
    unsigned ret = 0;
    for (unsigned i = 0; i < len; ++i)
    {
        ret *= (1 + 4 + 16);
        ret ^= buf[i];
    }
    return ret & 0xFFFFFF;
}

/// Finds if the current trace exists in the trace map.
/// @param hash is the previously computed hash value for the current trace.
/// @return nullptr if the current trace is not matching anything in the trace
/// buffer, otherwise the storage pointer to the copy of the current trace in
/// the trace buffer.
struct trace *find_current_trace(unsigned hash)
{
    for (struct trace *t = all_traces; t; t = t->next)
    {
        if (t->hash != (hash & 0xFFFFFF))
            continue;
        if (t->len != strace_len)
            continue;
        unsigned *payload = (unsigned *)(t + 1);
        if (memcmp(payload, stacktrace, strace_len * sizeof(stacktrace[0])) !=
            0)
            continue;
        return t;
    }
    return nullptr;
}

/// Adds the current trace to the trace buffer.
/// @param hash is the hash value ofthe current trace.
/// @return pointer to the trace in the trace buffer. The stats of the new
/// entry are not yet updated. Returns nullptr if the trace buffer is full.
struct trace *add_new_trace(unsigned hash)
{
    unsigned total_size = sizeof(struct trace) + strace_len * sizeof(stacktrace[0]);
    struct trace* t = (struct trace*)allocator.alloc(total_size);
    if (!t) return nullptr;
    memcpy(t + 1, stacktrace, strace_len * sizeof(stacktrace[0]));
    t->hash = hash;
    t->len = strace_len;
    t->total_size = 0;
    t->next = all_traces;
    all_traces = t;
    return t;
}

/// Current stacktrace buffer. This will be written from an interrupt.
void *stacktrace[MAX_STRACE];
/// Number of entries in stacktrace.
int strace_len;

/// This struct definition mimics the internal structures of libgcc in
/// arm-none-eabi binary. It's not portable and might break in the future.
struct core_regs
{
  unsigned r[16];
};

/// This struct definition mimics the internal structures of libgcc in
/// arm-none-eabi binary. It's not portable and might break in the future.
typedef struct
{
  unsigned demand_save_flags;
  struct core_regs core;
} phase2_vrs;

/// We store what we know about the external context at interrupt entry in this
/// structure.
phase2_vrs main_context;
/// Saved value of the lr register at the exception entry.
unsigned saved_lr;

/// Takes registers from the core state and the saved exception context and
/// fills in the structure necessary for the LIBGCC unwinder.
void fill_phase2_vrs(volatile unsigned* fault_args) {
    main_context.demand_save_flags = 0;
    main_context.core.r[0] = fault_args[0];
    main_context.core.r[1] = fault_args[1];
    main_context.core.r[2] = fault_args[2];
    main_context.core.r[3] = fault_args[3];
    main_context.core.r[12] = fault_args[4];
    // We add +2 here because first thing libgcc does with the lr value is
    // subtract two, presuming that lr points to after a branch
    // instruction. However, exception entry's saved PC can point to the first
    // instruction of a function and we don't want to have the backtrace end up
    // showing the previous function.
    main_context.core.r[14] = fault_args[6] + 2;
    main_context.core.r[15] = fault_args[6];
    saved_lr = fault_args[5];
    main_context.core.r[13] = (unsigned)(fault_args + 8); // stack pointer
}
extern "C" {
_Unwind_Reason_Code
__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument,
                       phase2_vrs * entry_vrs);
}

/// Static variable for trace_func.
void* last_ip;

/// Callback from the unwind backtrace function.
_Unwind_Reason_Code trace_func(struct _Unwind_Context *context, void *arg)
{
    void *ip;
    ip = (void *)_Unwind_GetIP(context);
    if (strace_len == 0)
    {
        //stacktrace[strace_len++] = ip;
        // By taking the beginning of the function for the immediate interrupt
        // we will attempt to coalesce more traces.
        //ip = (void *)_Unwind_GetRegionStart(context);
    }
    else if (last_ip == ip)
    {
        if (strace_len == 1 && saved_lr != _Unwind_GetGR (context, 14)) {
            _Unwind_SetGR (context, 14, saved_lr);
            allocator.singleLenHack++;
            return _URC_NO_REASON;
        }
        return _URC_END_OF_STACK;
    }
    if (strace_len >= MAX_STRACE-1)
    {
        ++allocator.limitReached;
        return _URC_END_OF_STACK;
    }
    //stacktrace[strace_len++] = ip;
    last_ip = ip;
    ip = (void *)_Unwind_GetRegionStart(context);
    stacktrace[strace_len++] = ip;
    return _URC_NO_REASON;
}

/// Called from the interrupt handler to take a CPU trace for the current
/// exception.
void take_cpu_trace()
{
    memset(stacktrace, 0, sizeof(stacktrace));
    strace_len = 0;
    last_ip = nullptr;
    phase2_vrs first_context = main_context;
    __gnu_Unwind_Backtrace(&trace_func, 0, &first_context);
    // This is a workaround for the case when the function in which we had the
    // exception trigger does not have a stack saved LR. In this case the
    // backtrace will fail after the first step. We manually append the second
    // step to have at least some idea of what's going on.
    if (strace_len == 1) {
        main_context.core.r[14] = saved_lr;
        main_context.core.r[15] = saved_lr;
        __gnu_Unwind_Backtrace(&trace_func, 0, &main_context);
    }
    unsigned h = hash_trace(strace_len, (unsigned *)stacktrace);
    struct trace *t = find_current_trace(h);
    if (!t)
    {
        t = add_new_trace(h);
    }
    if (t)
    {
        t->total_size += 1;
    }
}

/// Change this value to runtime disable and enable the CPU profile gathering
/// code.
bool enable_profiling = 0;
volatile unsigned* exception_args;
volatile unsigned is_process;
volatile unsigned saved_sp;

/// Helper function to declare the CPU usage tick interrupt.
/// @param irq_handler_name is the name of the interrupt to declare, for example
/// timer4a_interrupt_handler.
/// @param CLEAR_IRQ_FLAG is a c++ statement or statements in { ... } that will
/// be executed before returning from the interrupt to clear the timer IRQ flag.
#define DEFINE_CPU_PROFILE_INTERRUPT_HANDLER(irq_handler_name, CLEAR_IRQ_FLAG) \
    extern "C"                                                                 \
    {                                                                          \
        void __attribute__((__noinline__)) load_monitor_interrupt_handler(     \
            /*volatile unsigned *exception_args, */ unsigned                   \
                exception_return_code)                                         \
        {                                                                      \
            if (enable_profiling)                                              \
            {                                                                  \
                fill_phase2_vrs(exception_args);                               \
                take_cpu_trace();                                              \
            }                                                                  \
            cpuload_tick(is_process & 4 ? 0 : 255);                            \
            CLEAR_IRQ_FLAG;                                                    \
        }                                                                      \
        void __attribute__((__naked__)) irq_handler_name(void)                 \
        {                                                                      \
            __asm volatile("mov  r0, %0 \n"                                    \
                           "str  r4, [r0, 4*4] \n"                             \
                           "str  r5, [r0, 5*4] \n"                             \
                           "str  r6, [r0, 6*4] \n"                             \
                           "str  r7, [r0, 7*4] \n"                             \
                           "str  r8, [r0, 8*4] \n"                             \
                           "str  r9, [r0, 9*4] \n"                             \
                           "str  r10, [r0, 10*4] \n"                           \
                           "str  r11, [r0, 11*4] \n"                           \
                           "str  r12, [r0, 12*4] \n"                           \
                           "str  r13, [r0, 13*4] \n"                           \
                           "str  r14, [r0, 14*4] \n"                           \
                           :                                                   \
                           : "r"(main_context.core.r)                          \
                           : "r0");                                            \
            __asm volatile(" tst   lr, #4               \n"                    \
                           " ite   eq                   \n"                    \
                           " mrseq r0, msp              \n"                    \
                           " mrsne r0, psp              \n"                    \
                           " ldr r1, =exception_args \n"                       \
                           " str r0, [r1] \n"                                  \
                           " ldr r1, =is_process \n"                           \
                           " str lr, [r1] \n"                                  \
                           " ldr r0,  =load_monitor_interrupt_handler  \n"     \
                           " bx  r0  \n"                                       \
                           :                                                   \
                           :                                                   \
                           : "r0", "r1");                                      \
        }                                                                      \
    }

#endif // _FREERTOS_DRIVERS_COMMON_CPU_PROFILE_HXX_
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <stdio.h>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/XMLUTF8Transcoder.hpp>
#include <xercesc/validators/datatype/AnyURIDatatypeValidator.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
AnyURIDatatypeValidator::AnyURIDatatypeValidator(MemoryManager* const manager)
:AbstractStringValidator(0, 0, 0, DatatypeValidator::AnyURI, manager)
{}

AnyURIDatatypeValidator::~AnyURIDatatypeValidator()
{
}

AnyURIDatatypeValidator::AnyURIDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*      const enums
                        , const int                           finalSet
                        , MemoryManager* const manager)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::AnyURI, manager)
{
    init(enums, manager);
}

DatatypeValidator* AnyURIDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefArrayVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet
                                    , MemoryManager* const manager)
{
    return (DatatypeValidator*) new (manager) AnyURIDatatypeValidator(this, facets, enums, finalSet, manager);
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------

void AnyURIDatatypeValidator::checkValueSpace(const XMLCh* const content
                                              , MemoryManager* const manager)
{
    bool validURI = true;

    // check 3.2.17.c0 must: URI (rfc 2396/2723)
    try
    {
        // Support for relative URLs
        // According to Java 1.1: URLs may also be specified with a
        // String and the URL object that it is related to.
        //
        const unsigned int len = XMLString::stringLen(content);
        if (len)
        {
            // Encode special characters using XLink 5.4 algorithm
            XMLCh* encoded = (XMLCh*)manager->allocate((len*3+1) * sizeof(XMLCh));
            ArrayJanitor<XMLCh> encodedJan(encoded);
            encode(content, len, encoded, manager);
            validURI = XMLUri::isValidURI(true, encoded, true);
        }
    }
    catch(const OutOfMemoryException&)
    {
        throw;
    }
    catch (...)
    {
        ThrowXMLwithMemMgr1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_URI_Malformed
                , content
                , manager);
    }

    if (!validURI) {
        ThrowXMLwithMemMgr1(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_URI_Malformed
                    , content
                    , manager);
    }
}

/***
 * To encode special characters in anyURI, by using %HH to represent
 * special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', etc.
 * and non-ASCII characters (whose value >= 128).
 ***/
void AnyURIDatatypeValidator::encode(const XMLCh* const content, const XMLSize_t len, XMLCh* encoded, MemoryManager* const manager)
{
    static const bool needEscapeMap[] = {
        true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , /* 0x00 to 0x0F need escape */
        true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , /* 0x10 to 0x1F need escape */
        true , false, true , false, false, false, false, false, false, false, false, false, false, false, false, false, /* 0x20:' ', 0x22:'"' */
        false, false, false, false, false, false, false, false, false, false, false, false, true , false, true , false, /* 0x3C:'<', 0x3E:'>' */
        false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false, false, false, false, false, true , false, true , false, /* 0x5C:'\\', 0x5E:'^' */
        true , false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, /* 0x60:'`' */
        false, false, false, false, false, false, false, false, false, false, false, true , true , true , true , true   /* 0x7B:'{', 0x7C:'|', 0x7D:'}', 0x7E:'~', 0x7F:DEL */
    };

    int bufferIndex = 0;

    // For each character in content
    XMLSize_t i;
    for (i = 0; i < len; i++)
    {
        int ch = (int)content[i];
        // If it's not an ASCII character, break here, and use UTF-8 encoding
        if (ch >= 128)
            break;

        if (needEscapeMap[ch])
        {
            char tempStr[2] = "\0";
            sprintf(tempStr, "%02X", ch);
            encoded[bufferIndex++] = '%';
            encoded[bufferIndex++] = (XMLCh)tempStr[0];
            encoded[bufferIndex++] = (XMLCh)tempStr[1];
        }
        else
        {
            encoded[bufferIndex++] = (XMLCh)ch;
        }
    }

    // we saw some non-ascii character
    if (i < len) {
        // get UTF-8 bytes for the remaining sub-string
        const XMLCh* remContent = (XMLCh*)&content[i];
        const XMLSize_t remContentLen = len - i;
        XMLByte* UTF8Byte = (XMLByte*)manager->allocate((remContentLen*4+1) * sizeof(XMLByte));
        XMLSize_t charsEaten;

        XMLUTF8Transcoder transcoder(XMLUni::fgUTF8EncodingString, remContentLen*4+1, manager);
        transcoder.transcodeTo(remContent, remContentLen, UTF8Byte, remContentLen*4, charsEaten, XMLTranscoder::UnRep_RepChar);
        assert(charsEaten == remContentLen);

        XMLSize_t j;
        for (j = 0; j < remContentLen; j++) {
            XMLByte b = UTF8Byte[j];
            // for non-ascii character: make it positive, then escape
            if (b < 0) {
                int ch = b + 256;
                char tempStr[2] = "\0";
                sprintf(tempStr, "%02X", ch);
                encoded[bufferIndex++] = '%';
                encoded[bufferIndex++] = (XMLCh)tempStr[0];
                encoded[bufferIndex++] = (XMLCh)tempStr[1];
            }
            else if (needEscapeMap[b])
            {
                char tempStr[2] = "\0";
                sprintf(tempStr, "%02X", b);
                encoded[bufferIndex++] = '%';
                encoded[bufferIndex++] = (XMLCh)tempStr[0];
                encoded[bufferIndex++] = (XMLCh)tempStr[1];
            }
            else
            {
                encoded[bufferIndex++] = (XMLCh)b;
            }
        }
        manager->deallocate(UTF8Byte);
    }

    encoded[bufferIndex] = (XMLCh)0;
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(AnyURIDatatypeValidator)

void AnyURIDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    AbstractStringValidator::serialize(serEng);
}

XERCES_CPP_NAMESPACE_END

/**
  * End of file AnyURIDatatypeValidator.cpp
  */
<commit_msg>Pass in memory manager to janitor.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <stdio.h>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/XMLUTF8Transcoder.hpp>
#include <xercesc/validators/datatype/AnyURIDatatypeValidator.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
AnyURIDatatypeValidator::AnyURIDatatypeValidator(MemoryManager* const manager)
:AbstractStringValidator(0, 0, 0, DatatypeValidator::AnyURI, manager)
{}

AnyURIDatatypeValidator::~AnyURIDatatypeValidator()
{
}

AnyURIDatatypeValidator::AnyURIDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*      const enums
                        , const int                           finalSet
                        , MemoryManager* const manager)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::AnyURI, manager)
{
    init(enums, manager);
}

DatatypeValidator* AnyURIDatatypeValidator::newInstance(
                                      RefHashTableOf<KVStringPair>* const facets
                                    , RefArrayVectorOf<XMLCh>*           const enums
                                    , const int                           finalSet
                                    , MemoryManager* const manager)
{
    return (DatatypeValidator*) new (manager) AnyURIDatatypeValidator(this, facets, enums, finalSet, manager);
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------

void AnyURIDatatypeValidator::checkValueSpace(const XMLCh* const content
                                              , MemoryManager* const manager)
{
    bool validURI = true;

    // check 3.2.17.c0 must: URI (rfc 2396/2723)
    try
    {
        // Support for relative URLs
        // According to Java 1.1: URLs may also be specified with a
        // String and the URL object that it is related to.
        //
        const unsigned int len = XMLString::stringLen(content);
        if (len)
        {
            // Encode special characters using XLink 5.4 algorithm
            XMLCh* encoded = (XMLCh*)manager->allocate((len*3+1) * sizeof(XMLCh));
            ArrayJanitor<XMLCh> encodedJan(encoded, manager);
            encode(content, len, encoded, manager);
            validURI = XMLUri::isValidURI(true, encoded, true);
        }
    }
    catch(const OutOfMemoryException&)
    {
        throw;
    }
    catch (...)
    {
        ThrowXMLwithMemMgr1(InvalidDatatypeValueException
                , XMLExcepts::VALUE_URI_Malformed
                , content
                , manager);
    }

    if (!validURI) {
        ThrowXMLwithMemMgr1(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_URI_Malformed
                    , content
                    , manager);
    }
}

/***
 * To encode special characters in anyURI, by using %HH to represent
 * special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', etc.
 * and non-ASCII characters (whose value >= 128).
 ***/
void AnyURIDatatypeValidator::encode(const XMLCh* const content, const XMLSize_t len, XMLCh* encoded, MemoryManager* const manager)
{
    static const bool needEscapeMap[] = {
        true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , /* 0x00 to 0x0F need escape */
        true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , /* 0x10 to 0x1F need escape */
        true , false, true , false, false, false, false, false, false, false, false, false, false, false, false, false, /* 0x20:' ', 0x22:'"' */
        false, false, false, false, false, false, false, false, false, false, false, false, true , false, true , false, /* 0x3C:'<', 0x3E:'>' */
        false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false, false, false, false, false, true , false, true , false, /* 0x5C:'\\', 0x5E:'^' */
        true , false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, /* 0x60:'`' */
        false, false, false, false, false, false, false, false, false, false, false, true , true , true , true , true   /* 0x7B:'{', 0x7C:'|', 0x7D:'}', 0x7E:'~', 0x7F:DEL */
    };

    int bufferIndex = 0;

    // For each character in content
    XMLSize_t i;
    for (i = 0; i < len; i++)
    {
        int ch = (int)content[i];
        // If it's not an ASCII character, break here, and use UTF-8 encoding
        if (ch >= 128)
            break;

        if (needEscapeMap[ch])
        {
            char tempStr[2] = "\0";
            sprintf(tempStr, "%02X", ch);
            encoded[bufferIndex++] = '%';
            encoded[bufferIndex++] = (XMLCh)tempStr[0];
            encoded[bufferIndex++] = (XMLCh)tempStr[1];
        }
        else
        {
            encoded[bufferIndex++] = (XMLCh)ch;
        }
    }

    // we saw some non-ascii character
    if (i < len) {
        // get UTF-8 bytes for the remaining sub-string
        const XMLCh* remContent = (XMLCh*)&content[i];
        const XMLSize_t remContentLen = len - i;
        XMLByte* UTF8Byte = (XMLByte*)manager->allocate((remContentLen*4+1) * sizeof(XMLByte));
        XMLSize_t charsEaten;

        XMLUTF8Transcoder transcoder(XMLUni::fgUTF8EncodingString, remContentLen*4+1, manager);
        transcoder.transcodeTo(remContent, remContentLen, UTF8Byte, remContentLen*4, charsEaten, XMLTranscoder::UnRep_RepChar);
        assert(charsEaten == remContentLen);

        XMLSize_t j;
        for (j = 0; j < remContentLen; j++) {
            XMLByte b = UTF8Byte[j];
            // for non-ascii character: make it positive, then escape
            if (b < 0) {
                int ch = b + 256;
                char tempStr[2] = "\0";
                sprintf(tempStr, "%02X", ch);
                encoded[bufferIndex++] = '%';
                encoded[bufferIndex++] = (XMLCh)tempStr[0];
                encoded[bufferIndex++] = (XMLCh)tempStr[1];
            }
            else if (needEscapeMap[b])
            {
                char tempStr[2] = "\0";
                sprintf(tempStr, "%02X", b);
                encoded[bufferIndex++] = '%';
                encoded[bufferIndex++] = (XMLCh)tempStr[0];
                encoded[bufferIndex++] = (XMLCh)tempStr[1];
            }
            else
            {
                encoded[bufferIndex++] = (XMLCh)b;
            }
        }
        manager->deallocate(UTF8Byte);
    }

    encoded[bufferIndex] = (XMLCh)0;
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(AnyURIDatatypeValidator)

void AnyURIDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    AbstractStringValidator::serialize(serEng);
}

XERCES_CPP_NAMESPACE_END

/**
  * End of file AnyURIDatatypeValidator.cpp
  */
<|endoftext|>