<commit_before>/*
 * Copyright © 2015 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 "brw_context.h"
#include "brw_shader.h"
#include "brw_fs.h"
#include "brw_nir.h"
#include "brw_program.h"
#include "compiler/glsl/ir.h"
#include "compiler/glsl/ir_optimization.h"
#include "compiler/glsl/program.h"
#include "program/program.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/uniforms.h"

/**
 * Performs a compile of the shader stages even when we don't know
 * what non-orthogonal state will be set, in the hope that it reflects
 * the eventual NOS used, and thus allows us to produce link failures.
 */
static bool
brw_shader_precompile(struct gl_context *ctx,
                      struct gl_shader_program *sh_prog)
{
   struct gl_linked_shader *vs = sh_prog->_LinkedShaders[MESA_SHADER_VERTEX];
   struct gl_linked_shader *tcs = sh_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
   struct gl_linked_shader *tes = sh_prog->_LinkedShaders[MESA_SHADER_TESS_EVAL];
   struct gl_linked_shader *gs = sh_prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
   struct gl_linked_shader *fs = sh_prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
   struct gl_linked_shader *cs = sh_prog->_LinkedShaders[MESA_SHADER_COMPUTE];

   if (fs && !brw_fs_precompile(ctx, fs->Program))
      return false;

   if (gs && !brw_gs_precompile(ctx, gs->Program))
      return false;

   if (tes && !brw_tes_precompile(ctx, sh_prog, tes->Program))
      return false;

   if (tcs && !brw_tcs_precompile(ctx, sh_prog, tcs->Program))
      return false;

   if (vs && !brw_vs_precompile(ctx, vs->Program))
      return false;

   if (cs && !brw_cs_precompile(ctx, cs->Program))
      return false;

   return true;
}

static void
brw_lower_packing_builtins(struct brw_context *brw,
                           exec_list *ir)
{
   /* Gens < 7 don't have instructions to convert to or from half-precision,
    * and Gens < 6 don't expose that functionality.
    */
   if (brw->gen != 6)
      return;

   lower_packing_builtins(ir, LOWER_PACK_HALF_2x16 | LOWER_UNPACK_HALF_2x16);
}

static void
process_glsl_ir(struct brw_context *brw,
                struct gl_shader_program *shader_prog,
                struct gl_linked_shader *shader)
{
   struct gl_context *ctx = &brw->ctx;
   const struct brw_compiler *compiler = brw->screen->compiler;
   const struct gl_shader_compiler_options *options =
      &ctx->Const.ShaderCompilerOptions[shader->Stage];

   /* Temporary memory context for any new IR. */
   void *mem_ctx = ralloc_context(NULL);

   ralloc_adopt(mem_ctx, shader->ir);

   lower_blend_equation_advanced(shader);

   /* lower_packing_builtins() inserts arithmetic instructions, so it
    * must precede lower_instructions().
    */
   brw_lower_packing_builtins(brw, shader->ir);
   do_mat_op_to_vec(shader->ir);

   unsigned instructions_to_lower = (DIV_TO_MUL_RCP |
                                     SUB_TO_ADD_NEG |
                                     EXP_TO_EXP2 |
                                     LOG_TO_LOG2 |
                                     DFREXP_DLDEXP_TO_ARITH);
   if (brw->gen < 7) {
      instructions_to_lower |= BIT_COUNT_TO_MATH |
                               EXTRACT_TO_SHIFTS |
                               INSERT_TO_SHIFTS |
                               REVERSE_TO_SHIFTS;
   }

   lower_instructions(shader->ir, instructions_to_lower);

   /* Pre-gen6 HW can only nest if-statements 16 deep.  Beyond this,
    * if-statements need to be flattened.
    */
   if (brw->gen < 6)
      lower_if_to_cond_assign(shader->Stage, shader->ir, 16);

   do_lower_texture_projection(shader->ir);
   do_vec_index_to_cond_assign(shader->ir);
   lower_vector_insert(shader->ir, true);
   lower_offset_arrays(shader->ir);
   lower_noise(shader->ir);
   lower_quadop_vector(shader->ir, false);

   bool progress;
   do {
      progress = false;

      if (compiler->scalar_stage[shader->Stage]) {
         if (shader->Stage == MESA_SHADER_VERTEX ||
             shader->Stage == MESA_SHADER_FRAGMENT)
            brw_do_channel_expressions(shader->ir);
         brw_do_vector_splitting(shader->ir);
      }

      progress = do_common_optimization(shader->ir, true, true,
                                        options, ctx->Const.NativeIntegers) || progress;
   } while (progress);

   validate_ir_tree(shader->ir);

   /* Now that we've finished altering the linked IR, reparent any live IR back
    * to the permanent memory context, and free the temporary one (discarding any
    * junk we optimized away).
    */
   reparent_ir(shader->ir, shader->ir);
   ralloc_free(mem_ctx);

   if (ctx->_Shader->Flags & GLSL_DUMP) {
      fprintf(stderr, "\n");
      if (shader->ir) {
         fprintf(stderr, "GLSL IR for linked %s program %d:\n",
                 _mesa_shader_stage_to_string(shader->Stage),
                 shader_prog->Name);
         _mesa_print_ir(stderr, shader->ir, NULL);
      } else {
         fprintf(stderr, "No GLSL IR for linked %s program %d (shader may be "
                 "from cache)\n", _mesa_shader_stage_to_string(shader->Stage),
                 shader_prog->Name);
      }
      fprintf(stderr, "\n");
   }
}

static void
unify_interfaces(struct shader_info **infos)
{
   struct shader_info *prev_info = NULL;

   for (unsigned i = MESA_SHADER_VERTEX; i < MESA_SHADER_FRAGMENT; i++) {
      if (!infos[i])
         continue;

      if (prev_info) {
         prev_info->outputs_written |= infos[i]->inputs_read;
         prev_info->patch_outputs_written |= infos[i]->patch_inputs_read;
         infos[i]->inputs_read |= prev_info->outputs_written;
         infos[i]->patch_inputs_read |= prev_info->patch_outputs_written;
      }
      prev_info = infos[i];
   }
}

extern "C" GLboolean
brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg)
{
   struct brw_context *brw = brw_context(ctx);
   const struct brw_compiler *compiler = brw->screen->compiler;
   unsigned int stage;
   struct shader_info *infos[MESA_SHADER_STAGES] = { 0, };

   for (stage = 0; stage < ARRAY_SIZE(shProg->_LinkedShaders); stage++) {
      struct gl_linked_shader *shader = shProg->_LinkedShaders[stage];
      if (!shader)
         continue;

      struct gl_program *prog = shader->Program;
      prog->Parameters = _mesa_new_parameter_list();

      process_glsl_ir(brw, shProg, shader);

      _mesa_copy_linked_program_data(shProg, shader);

      prog->ShadowSamplers = shader->shadow_samplers;
      _mesa_update_shader_textures_used(shProg, prog);

      brw_add_texrect_params(prog);

      bool debug_enabled =
         (INTEL_DEBUG & intel_debug_flag_for_shader_stage(shader->Stage));

      if (debug_enabled && shader->ir) {
         fprintf(stderr, "GLSL IR for native %s shader %d:\n",
                 _mesa_shader_stage_to_string(shader->Stage), shProg->Name);
         _mesa_print_ir(stderr, shader->ir, NULL);
         fprintf(stderr, "\n\n");
      }

      prog->nir = brw_create_nir(brw, shProg, prog, (gl_shader_stage) stage,
                                 compiler->scalar_stage[stage]);
      infos[stage] = prog->nir->info;

      /* Make a pass over the IR to add state references for any built-in
       * uniforms that are used.  This has to be done now (during linking).
       * Code generation doesn't happen until the first time this shader is
       * used for rendering.  Waiting until then to generate the parameters is
       * too late.  At that point, the values for the built-in uniforms won't
       * get sent to the shader.
       */
      nir_foreach_variable(var, &prog->nir->uniforms) {
         if (strncmp(var->name, "gl_", 3) == 0) {
            const nir_state_slot *const slots = var->state_slots;
            assert(var->state_slots != NULL);

            for (unsigned int i = 0; i < var->num_state_slots; i++) {
               _mesa_add_state_reference(prog->Parameters,
                                         (gl_state_index *)slots[i].tokens);
            }
         }
      }
   }

   /* The linker tries to dead code eliminate unused varying components,
    * and make sure interfaces match.  But it isn't able to do so in all
    * cases.  So, explicitly make the interfaces match by OR'ing together
    * the inputs_read/outputs_written bitfields of adjacent stages.
    */
   if (!shProg->SeparateShader)
      unify_interfaces(infos);

   if ((ctx->_Shader->Flags & GLSL_DUMP) && shProg->Name != 0) {
      for (unsigned i = 0; i < shProg->NumShaders; i++) {
         const struct gl_shader *sh = shProg->Shaders[i];
         if (!sh)
            continue;

         fprintf(stderr, "GLSL %s shader %d source for linked program %d:\n",
                 _mesa_shader_stage_to_string(sh->Stage),
                 i, shProg->Name);
         fprintf(stderr, "%s", sh->Source);
         fprintf(stderr, "\n");
      }
   }

   if (brw->precompile && !brw_shader_precompile(ctx, shProg))
      return false;

   build_program_resource_list(ctx, shProg);

   for (stage = 0; stage < ARRAY_SIZE(shProg->_LinkedShaders); stage++) {
      struct gl_linked_shader *shader = shProg->_LinkedShaders[stage];
      if (!shader)
         continue;

      /* The GLSL IR won't be needed anymore. */
      ralloc_free(shader->ir);
      shader->ir = NULL;
   }

   return true;
}
<commit_msg>i965: Make unify_interfaces not spread VARYING_BIT_TESS_LEVEL_*.<commit_after>/*
 * Copyright © 2015 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 "brw_context.h"
#include "brw_shader.h"
#include "brw_fs.h"
#include "brw_nir.h"
#include "brw_program.h"
#include "compiler/glsl/ir.h"
#include "compiler/glsl/ir_optimization.h"
#include "compiler/glsl/program.h"
#include "program/program.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/uniforms.h"

/**
 * Performs a compile of the shader stages even when we don't know
 * what non-orthogonal state will be set, in the hope that it reflects
 * the eventual NOS used, and thus allows us to produce link failures.
 */
static bool
brw_shader_precompile(struct gl_context *ctx,
                      struct gl_shader_program *sh_prog)
{
   struct gl_linked_shader *vs = sh_prog->_LinkedShaders[MESA_SHADER_VERTEX];
   struct gl_linked_shader *tcs = sh_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
   struct gl_linked_shader *tes = sh_prog->_LinkedShaders[MESA_SHADER_TESS_EVAL];
   struct gl_linked_shader *gs = sh_prog->_LinkedShaders[MESA_SHADER_GEOMETRY];
   struct gl_linked_shader *fs = sh_prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
   struct gl_linked_shader *cs = sh_prog->_LinkedShaders[MESA_SHADER_COMPUTE];

   if (fs && !brw_fs_precompile(ctx, fs->Program))
      return false;

   if (gs && !brw_gs_precompile(ctx, gs->Program))
      return false;

   if (tes && !brw_tes_precompile(ctx, sh_prog, tes->Program))
      return false;

   if (tcs && !brw_tcs_precompile(ctx, sh_prog, tcs->Program))
      return false;

   if (vs && !brw_vs_precompile(ctx, vs->Program))
      return false;

   if (cs && !brw_cs_precompile(ctx, cs->Program))
      return false;

   return true;
}

static void
brw_lower_packing_builtins(struct brw_context *brw,
                           exec_list *ir)
{
   /* Gens < 7 don't have instructions to convert to or from half-precision,
    * and Gens < 6 don't expose that functionality.
    */
   if (brw->gen != 6)
      return;

   lower_packing_builtins(ir, LOWER_PACK_HALF_2x16 | LOWER_UNPACK_HALF_2x16);
}

static void
process_glsl_ir(struct brw_context *brw,
                struct gl_shader_program *shader_prog,
                struct gl_linked_shader *shader)
{
   struct gl_context *ctx = &brw->ctx;
   const struct brw_compiler *compiler = brw->screen->compiler;
   const struct gl_shader_compiler_options *options =
      &ctx->Const.ShaderCompilerOptions[shader->Stage];

   /* Temporary memory context for any new IR. */
   void *mem_ctx = ralloc_context(NULL);

   ralloc_adopt(mem_ctx, shader->ir);

   lower_blend_equation_advanced(shader);

   /* lower_packing_builtins() inserts arithmetic instructions, so it
    * must precede lower_instructions().
    */
   brw_lower_packing_builtins(brw, shader->ir);
   do_mat_op_to_vec(shader->ir);

   unsigned instructions_to_lower = (DIV_TO_MUL_RCP |
                                     SUB_TO_ADD_NEG |
                                     EXP_TO_EXP2 |
                                     LOG_TO_LOG2 |
                                     DFREXP_DLDEXP_TO_ARITH);
   if (brw->gen < 7) {
      instructions_to_lower |= BIT_COUNT_TO_MATH |
                               EXTRACT_TO_SHIFTS |
                               INSERT_TO_SHIFTS |
                               REVERSE_TO_SHIFTS;
   }

   lower_instructions(shader->ir, instructions_to_lower);

   /* Pre-gen6 HW can only nest if-statements 16 deep.  Beyond this,
    * if-statements need to be flattened.
    */
   if (brw->gen < 6)
      lower_if_to_cond_assign(shader->Stage, shader->ir, 16);

   do_lower_texture_projection(shader->ir);
   do_vec_index_to_cond_assign(shader->ir);
   lower_vector_insert(shader->ir, true);
   lower_offset_arrays(shader->ir);
   lower_noise(shader->ir);
   lower_quadop_vector(shader->ir, false);

   bool progress;
   do {
      progress = false;

      if (compiler->scalar_stage[shader->Stage]) {
         if (shader->Stage == MESA_SHADER_VERTEX ||
             shader->Stage == MESA_SHADER_FRAGMENT)
            brw_do_channel_expressions(shader->ir);
         brw_do_vector_splitting(shader->ir);
      }

      progress = do_common_optimization(shader->ir, true, true,
                                        options, ctx->Const.NativeIntegers) || progress;
   } while (progress);

   validate_ir_tree(shader->ir);

   /* Now that we've finished altering the linked IR, reparent any live IR back
    * to the permanent memory context, and free the temporary one (discarding any
    * junk we optimized away).
    */
   reparent_ir(shader->ir, shader->ir);
   ralloc_free(mem_ctx);

   if (ctx->_Shader->Flags & GLSL_DUMP) {
      fprintf(stderr, "\n");
      if (shader->ir) {
         fprintf(stderr, "GLSL IR for linked %s program %d:\n",
                 _mesa_shader_stage_to_string(shader->Stage),
                 shader_prog->Name);
         _mesa_print_ir(stderr, shader->ir, NULL);
      } else {
         fprintf(stderr, "No GLSL IR for linked %s program %d (shader may be "
                 "from cache)\n", _mesa_shader_stage_to_string(shader->Stage),
                 shader_prog->Name);
      }
      fprintf(stderr, "\n");
   }
}

static void
unify_interfaces(struct shader_info **infos)
{
   struct shader_info *prev_info = NULL;

   for (unsigned i = MESA_SHADER_VERTEX; i < MESA_SHADER_FRAGMENT; i++) {
      if (!infos[i])
         continue;

      if (prev_info) {
         prev_info->outputs_written |= infos[i]->inputs_read &
            ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);
         infos[i]->inputs_read |= prev_info->outputs_written &
            ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);

         prev_info->patch_outputs_written |= infos[i]->patch_inputs_read;
         infos[i]->patch_inputs_read |= prev_info->patch_outputs_written;
      }
      prev_info = infos[i];
   }
}

extern "C" GLboolean
brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg)
{
   struct brw_context *brw = brw_context(ctx);
   const struct brw_compiler *compiler = brw->screen->compiler;
   unsigned int stage;
   struct shader_info *infos[MESA_SHADER_STAGES] = { 0, };

   for (stage = 0; stage < ARRAY_SIZE(shProg->_LinkedShaders); stage++) {
      struct gl_linked_shader *shader = shProg->_LinkedShaders[stage];
      if (!shader)
         continue;

      struct gl_program *prog = shader->Program;
      prog->Parameters = _mesa_new_parameter_list();

      process_glsl_ir(brw, shProg, shader);

      _mesa_copy_linked_program_data(shProg, shader);

      prog->ShadowSamplers = shader->shadow_samplers;
      _mesa_update_shader_textures_used(shProg, prog);

      brw_add_texrect_params(prog);

      bool debug_enabled =
         (INTEL_DEBUG & intel_debug_flag_for_shader_stage(shader->Stage));

      if (debug_enabled && shader->ir) {
         fprintf(stderr, "GLSL IR for native %s shader %d:\n",
                 _mesa_shader_stage_to_string(shader->Stage), shProg->Name);
         _mesa_print_ir(stderr, shader->ir, NULL);
         fprintf(stderr, "\n\n");
      }

      prog->nir = brw_create_nir(brw, shProg, prog, (gl_shader_stage) stage,
                                 compiler->scalar_stage[stage]);
      infos[stage] = prog->nir->info;

      /* Make a pass over the IR to add state references for any built-in
       * uniforms that are used.  This has to be done now (during linking).
       * Code generation doesn't happen until the first time this shader is
       * used for rendering.  Waiting until then to generate the parameters is
       * too late.  At that point, the values for the built-in uniforms won't
       * get sent to the shader.
       */
      nir_foreach_variable(var, &prog->nir->uniforms) {
         if (strncmp(var->name, "gl_", 3) == 0) {
            const nir_state_slot *const slots = var->state_slots;
            assert(var->state_slots != NULL);

            for (unsigned int i = 0; i < var->num_state_slots; i++) {
               _mesa_add_state_reference(prog->Parameters,
                                         (gl_state_index *)slots[i].tokens);
            }
         }
      }
   }

   /* The linker tries to dead code eliminate unused varying components,
    * and make sure interfaces match.  But it isn't able to do so in all
    * cases.  So, explicitly make the interfaces match by OR'ing together
    * the inputs_read/outputs_written bitfields of adjacent stages.
    */
   if (!shProg->SeparateShader)
      unify_interfaces(infos);

   if ((ctx->_Shader->Flags & GLSL_DUMP) && shProg->Name != 0) {
      for (unsigned i = 0; i < shProg->NumShaders; i++) {
         const struct gl_shader *sh = shProg->Shaders[i];
         if (!sh)
            continue;

         fprintf(stderr, "GLSL %s shader %d source for linked program %d:\n",
                 _mesa_shader_stage_to_string(sh->Stage),
                 i, shProg->Name);
         fprintf(stderr, "%s", sh->Source);
         fprintf(stderr, "\n");
      }
   }

   if (brw->precompile && !brw_shader_precompile(ctx, shProg))
      return false;

   build_program_resource_list(ctx, shProg);

   for (stage = 0; stage < ARRAY_SIZE(shProg->_LinkedShaders); stage++) {
      struct gl_linked_shader *shader = shProg->_LinkedShaders[stage];
      if (!shader)
         continue;

      /* The GLSL IR won't be needed anymore. */
      ralloc_free(shader->ir);
      shader->ir = NULL;
   }

   return true;
}
<|endoftext|>


<commit_before>//
// OpenFlight loader for OpenSceneGraph
//
//  Copyright (C) 2005-2006  Brede Johansen
//

#include <stdexcept>
#include <osg/Notify>
#include <osg/ProxyNode>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/ReentrantMutex>
#include <osgUtil/Optimizer>

#include "Registry.h"
#include "Document.h"
#include "RecordInputStream.h"

#define SERIALIZER() OpenThreads::ScopedLock<osgDB::ReentrantMutex> lock(_serializerMutex)

using namespace flt;
using namespace osg;
using namespace osgDB;

class ReadExternalsVisitor : public osg::NodeVisitor
{
    osg::ref_ptr<ReaderWriter::Options> _options;
    bool _cloneExternalReferences;

public:

    ReadExternalsVisitor(ReaderWriter::Options* options) :
        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
        _options(options),
        _cloneExternalReferences(false)
    {
        if (options)
            _cloneExternalReferences = (options->getOptionString().find("cloneExternalReferences")!=std::string::npos);
    }

    virtual ~ReadExternalsVisitor() {}

    virtual void apply(ProxyNode& node)
    {
        // Transfer ownership of pools.
        _options->setUserData( node.getUserData() );
        node.setUserData(NULL);

        for (unsigned int pos=0; pos<node.getNumFileNames(); pos++)
        {
            std::string filename = node.getFileName(pos);

            // read external
            osg::ref_ptr<osg::Node> external = osgDB::readNodeFile(filename,_options.get());
            if (external.valid())
            {
                if (_cloneExternalReferences)
                    external = dynamic_cast<osg::Node*>(external->clone(osg::CopyOp(osg::CopyOp::DEEP_COPY_NODES)));

                node.addChild(external.get());
            }
        }
    }
};

class FLTReaderWriter : public ReaderWriter
{
    public:
        virtual const char* className() const { return "FLT Reader/Writer"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return equalCaseInsensitive(extension,"flt");
        }

        virtual ReadResult readObject(const std::string& file, const Options* options) const
        {
            return readNode(file, options);
        }

        virtual ReadResult readNode(const std::string& file, const Options* options) const
        {
            SERIALIZER();

            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile(file, options);
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            // in local cache?
            {
                osg::Node* node = flt::Registry::instance()->getExternalFromLocalCache(fileName);
                if (node)
                    return ReadResult(node, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
            }

            // setting up the database path so that internally referenced file are searched for on relative paths.
            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
            local_opt->setDatabasePath(osgDB::getFilePath(fileName));

            ReadResult rr;

            // read file
            {
                std::ifstream istream;
                istream.imbue(std::locale::classic());
                istream.open(fileName.c_str(), std::ios::in | std::ios::binary);

                if (istream)
                {
                    rr = readNode(istream,local_opt.get());
                }
            }

            static int nestedExternalsLevel = 0;
            if (rr.success())
            {
                // add to local cache.
                flt::Registry::instance()->addExternalToLocalCache(fileName,rr.getNode());

                bool keepExternalReferences = false;
                if (options)
                    keepExternalReferences = (options->getOptionString().find("keepExternalReferences")!=std::string::npos);

                if ( !keepExternalReferences )
                {
                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences not found, so externals will be re-readed"<<std::endl;
                    // read externals.
                    if (rr.getNode())
                    {
                        nestedExternalsLevel++;
                        ReadExternalsVisitor visitor(local_opt.get());
                        rr.getNode()->accept(visitor);
                        nestedExternalsLevel--;
                    }
                }
                else
                {
                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences found, so externals will be left as ProxyNodes"<<std::endl;
                }
            }

            // clear local cache.
            if (nestedExternalsLevel==0)
                flt::Registry::instance()->clearLocalCache();

            return rr;
        }

        virtual ReadResult readObject(std::istream& fin, const Options* options) const
        {
            return readNode(fin, options);
        }

        virtual ReadResult readNode(std::istream& fin, const Options* options) const
        {
            Document document;
            document.setOptions(options);

            // option string and parent pools
            if (options)
            {
                const char readerMsg[] = "flt reader option: ";

                document.setReplaceClampWithClampToEdge((options->getOptionString().find("clampToEdge")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "clampToEdge=" << document.getReplaceClampWithClampToEdge() << std::endl;

                document.setKeepExternalReferences((options->getOptionString().find("keepExternalReferences")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "keepExternalReferences=" << document.getKeepExternalReferences() << std::endl;

                document.setPreserveFace((options->getOptionString().find("preserveFace")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveFace=" << document.getPreserveFace() << std::endl;

                document.setPreserveObject((options->getOptionString().find("preserveObject")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveObject=" << document.getPreserveObject() << std::endl;

                document.setDefaultDOFAnimationState((options->getOptionString().find("dofAnimation")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "dofAnimation=" << document.getDefaultDOFAnimationState() << std::endl;

                document.setUseBillboardCenter((options->getOptionString().find("billboardCenter")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "billboardCenter=" << document.getUseBillboardCenter() << std::endl;

                document.setUseTextureAlphaForTransparancyBinning(options->getOptionString().find("noTextureAlphaForTransparancyBinning")==std::string::npos);
                osg::notify(osg::DEBUG_INFO) << readerMsg << "noTextureAlphaForTransparancyBinning=" << !document.getUseTextureAlphaForTransparancyBinning() << std::endl;

                document.setDoUnitsConversion((options->getOptionString().find("noUnitsConversion")==std::string::npos)); // default to true, unless noUnitsConversion is specified.
                osg::notify(osg::DEBUG_INFO) << readerMsg << "noUnitsConversion=" << !document.getDoUnitsConversion() << std::endl;

                if (document.getDoUnitsConversion())
                {
                    if (options->getOptionString().find("convertToFeet")!=std::string::npos)
                        document.setDesiredUnits(FEET);
                    else if (options->getOptionString().find("convertToInches")!=std::string::npos)
                        document.setDesiredUnits(INCHES);
                    else if (options->getOptionString().find("convertToMeters")!=std::string::npos)
                        document.setDesiredUnits(METERS);
                    else if (options->getOptionString().find("convertToKilometers")!=std::string::npos)
                        document.setDesiredUnits(KILOMETERS);
                    else if (options->getOptionString().find("convertToNauticalMiles")!=std::string::npos)
                        document.setDesiredUnits(NAUTICAL_MILES);
                }

                const ParentPools* pools = dynamic_cast<const ParentPools*>( options->getUserData() );
                if (pools)
                {
                    // This file is an external reference. The individual pools will
                    // be non-NULL if the parent is overriding the ext ref model's pools.
                    if (pools->getColorPool())
                        document.setColorPool( pools->getColorPool(), true );
                    if (pools->getTexturePool())
                        document.setTexturePool( pools->getTexturePool(), true );
                    if (pools->getMaterialPool())
                        document.setMaterialPool( pools->getMaterialPool(), true );
                    if (pools->getLightSourcePool())
                        document.setLightSourcePool( pools->getLightSourcePool(), true );
                    if (pools->getLPAppearancePool())
                        document.setLightPointAppearancePool( pools->getLPAppearancePool(), true );
                    if (pools->getShaderPool())
                        document.setShaderPool( pools->getShaderPool(), true );
                }
            }

            {
                // read records
                flt::RecordInputStream recordStream(fin.rdbuf());
                while (recordStream.good() && !document.done())
                {
                    recordStream.readRecord(document);
                }
            }

            if (!document.getHeaderNode())
                return ReadResult::ERROR_IN_READING_FILE;

            if (!document.getPreserveFace())
            {
                osgUtil::Optimizer optimizer;
                optimizer.optimize(document.getHeaderNode(),  osgUtil::Optimizer::SHARE_DUPLICATE_STATE | osgUtil::Optimizer::MERGE_GEOMETRY | osgUtil::Optimizer::MERGE_GEODES | osgUtil::Optimizer::TESSELLATE_GEOMETRY );
            }

            return document.getHeaderNode();
        }

        virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            const Node* node = dynamic_cast<const Node*>(&object);
            if (node) return writeNode( *node, fileName, options );
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeNode(const Node& /*node*/,const std::string& /*fileName*/, const osgDB::ReaderWriter::Options* /*options*/) const
        {
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const
        {
            const Node* node = dynamic_cast<const Node*>(&object);
            if (node) return writeNode( *node, fout, options );
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeNode(const Node& /*node*/,std::ostream& /*fout*/, const osgDB::ReaderWriter::Options* /*options*/) const
        {
            return WriteResult::FILE_NOT_HANDLED;
        }

    protected:

        mutable osgDB::ReentrantMutex _serializerMutex;
};

// now register with Registry to instantiate the above
// reader/writer.
RegisterReaderWriterProxy<FLTReaderWriter> g_FLTReaderWriterProxy;

<commit_msg>Added STATIC_OBJECT_DETECTION optimizer pass to OpenFlight plugin<commit_after>//
// OpenFlight loader for OpenSceneGraph
//
//  Copyright (C) 2005-2006  Brede Johansen
//

#include <stdexcept>
#include <osg/Notify>
#include <osg/ProxyNode>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/ReentrantMutex>
#include <osgUtil/Optimizer>

#include "Registry.h"
#include "Document.h"
#include "RecordInputStream.h"

#define SERIALIZER() OpenThreads::ScopedLock<osgDB::ReentrantMutex> lock(_serializerMutex)

using namespace flt;
using namespace osg;
using namespace osgDB;

class ReadExternalsVisitor : public osg::NodeVisitor
{
    osg::ref_ptr<ReaderWriter::Options> _options;
    bool _cloneExternalReferences;

public:

    ReadExternalsVisitor(ReaderWriter::Options* options) :
        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
        _options(options),
        _cloneExternalReferences(false)
    {
        if (options)
            _cloneExternalReferences = (options->getOptionString().find("cloneExternalReferences")!=std::string::npos);
    }

    virtual ~ReadExternalsVisitor() {}

    virtual void apply(ProxyNode& node)
    {
        // Transfer ownership of pools.
        _options->setUserData( node.getUserData() );
        node.setUserData(NULL);

        for (unsigned int pos=0; pos<node.getNumFileNames(); pos++)
        {
            std::string filename = node.getFileName(pos);

            // read external
            osg::ref_ptr<osg::Node> external = osgDB::readNodeFile(filename,_options.get());
            if (external.valid())
            {
                if (_cloneExternalReferences)
                    external = dynamic_cast<osg::Node*>(external->clone(osg::CopyOp(osg::CopyOp::DEEP_COPY_NODES)));

                node.addChild(external.get());
            }
        }
    }
};

class FLTReaderWriter : public ReaderWriter
{
    public:
        virtual const char* className() const { return "FLT Reader/Writer"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return equalCaseInsensitive(extension,"flt");
        }

        virtual ReadResult readObject(const std::string& file, const Options* options) const
        {
            return readNode(file, options);
        }

        virtual ReadResult readNode(const std::string& file, const Options* options) const
        {
            SERIALIZER();

            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile(file, options);
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            // in local cache?
            {
                osg::Node* node = flt::Registry::instance()->getExternalFromLocalCache(fileName);
                if (node)
                    return ReadResult(node, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
            }

            // setting up the database path so that internally referenced file are searched for on relative paths.
            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
            local_opt->setDatabasePath(osgDB::getFilePath(fileName));

            ReadResult rr;

            // read file
            {
                std::ifstream istream;
                istream.imbue(std::locale::classic());
                istream.open(fileName.c_str(), std::ios::in | std::ios::binary);

                if (istream)
                {
                    rr = readNode(istream,local_opt.get());
                }
            }

            static int nestedExternalsLevel = 0;
            if (rr.success())
            {
                // add to local cache.
                flt::Registry::instance()->addExternalToLocalCache(fileName,rr.getNode());

                bool keepExternalReferences = false;
                if (options)
                    keepExternalReferences = (options->getOptionString().find("keepExternalReferences")!=std::string::npos);

                if ( !keepExternalReferences )
                {
                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences not found, so externals will be re-readed"<<std::endl;
                    // read externals.
                    if (rr.getNode())
                    {
                        nestedExternalsLevel++;
                        ReadExternalsVisitor visitor(local_opt.get());
                        rr.getNode()->accept(visitor);
                        nestedExternalsLevel--;
                    }
                }
                else
                {
                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences found, so externals will be left as ProxyNodes"<<std::endl;
                }
            }

            // clear local cache.
            if (nestedExternalsLevel==0)
                flt::Registry::instance()->clearLocalCache();

            return rr;
        }

        virtual ReadResult readObject(std::istream& fin, const Options* options) const
        {
            return readNode(fin, options);
        }

        virtual ReadResult readNode(std::istream& fin, const Options* options) const
        {
            Document document;
            document.setOptions(options);

            // option string and parent pools
            if (options)
            {
                const char readerMsg[] = "flt reader option: ";

                document.setReplaceClampWithClampToEdge((options->getOptionString().find("clampToEdge")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "clampToEdge=" << document.getReplaceClampWithClampToEdge() << std::endl;

                document.setKeepExternalReferences((options->getOptionString().find("keepExternalReferences")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "keepExternalReferences=" << document.getKeepExternalReferences() << std::endl;

                document.setPreserveFace((options->getOptionString().find("preserveFace")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveFace=" << document.getPreserveFace() << std::endl;

                document.setPreserveObject((options->getOptionString().find("preserveObject")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveObject=" << document.getPreserveObject() << std::endl;

                document.setDefaultDOFAnimationState((options->getOptionString().find("dofAnimation")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "dofAnimation=" << document.getDefaultDOFAnimationState() << std::endl;

                document.setUseBillboardCenter((options->getOptionString().find("billboardCenter")!=std::string::npos));
                osg::notify(osg::DEBUG_INFO) << readerMsg << "billboardCenter=" << document.getUseBillboardCenter() << std::endl;

                document.setUseTextureAlphaForTransparancyBinning(options->getOptionString().find("noTextureAlphaForTransparancyBinning")==std::string::npos);
                osg::notify(osg::DEBUG_INFO) << readerMsg << "noTextureAlphaForTransparancyBinning=" << !document.getUseTextureAlphaForTransparancyBinning() << std::endl;

                document.setDoUnitsConversion((options->getOptionString().find("noUnitsConversion")==std::string::npos)); // default to true, unless noUnitsConversion is specified.
                osg::notify(osg::DEBUG_INFO) << readerMsg << "noUnitsConversion=" << !document.getDoUnitsConversion() << std::endl;

                if (document.getDoUnitsConversion())
                {
                    if (options->getOptionString().find("convertToFeet")!=std::string::npos)
                        document.setDesiredUnits(FEET);
                    else if (options->getOptionString().find("convertToInches")!=std::string::npos)
                        document.setDesiredUnits(INCHES);
                    else if (options->getOptionString().find("convertToMeters")!=std::string::npos)
                        document.setDesiredUnits(METERS);
                    else if (options->getOptionString().find("convertToKilometers")!=std::string::npos)
                        document.setDesiredUnits(KILOMETERS);
                    else if (options->getOptionString().find("convertToNauticalMiles")!=std::string::npos)
                        document.setDesiredUnits(NAUTICAL_MILES);
                }

                const ParentPools* pools = dynamic_cast<const ParentPools*>( options->getUserData() );
                if (pools)
                {
                    // This file is an external reference. The individual pools will
                    // be non-NULL if the parent is overriding the ext ref model's pools.
                    if (pools->getColorPool())
                        document.setColorPool( pools->getColorPool(), true );
                    if (pools->getTexturePool())
                        document.setTexturePool( pools->getTexturePool(), true );
                    if (pools->getMaterialPool())
                        document.setMaterialPool( pools->getMaterialPool(), true );
                    if (pools->getLightSourcePool())
                        document.setLightSourcePool( pools->getLightSourcePool(), true );
                    if (pools->getLPAppearancePool())
                        document.setLightPointAppearancePool( pools->getLPAppearancePool(), true );
                    if (pools->getShaderPool())
                        document.setShaderPool( pools->getShaderPool(), true );
                }
            }

            {
                // read records
                flt::RecordInputStream recordStream(fin.rdbuf());
                while (recordStream.good() && !document.done())
                {
                    recordStream.readRecord(document);
                }
            }

            if (!document.getHeaderNode())
                return ReadResult::ERROR_IN_READING_FILE;

            if (!document.getPreserveFace())
            {
                osgUtil::Optimizer optimizer;
                optimizer.optimize(document.getHeaderNode(),
                    osgUtil::Optimizer::SHARE_DUPLICATE_STATE |
                    osgUtil::Optimizer::MERGE_GEOMETRY |
                    osgUtil::Optimizer::MERGE_GEODES |
                    osgUtil::Optimizer::TESSELLATE_GEOMETRY |
                    osgUtil::Optimizer::STATIC_OBJECT_DETECTION);
            }

            return document.getHeaderNode();
        }

        virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
        {
            const Node* node = dynamic_cast<const Node*>(&object);
            if (node) return writeNode( *node, fileName, options );
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeNode(const Node& /*node*/,const std::string& /*fileName*/, const osgDB::ReaderWriter::Options* /*options*/) const
        {
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const
        {
            const Node* node = dynamic_cast<const Node*>(&object);
            if (node) return writeNode( *node, fout, options );
            return WriteResult::FILE_NOT_HANDLED;
        }

        virtual WriteResult writeNode(const Node& /*node*/,std::ostream& /*fout*/, const osgDB::ReaderWriter::Options* /*options*/) const
        {
            return WriteResult::FILE_NOT_HANDLED;
        }

    protected:

        mutable osgDB::ReentrantMutex _serializerMutex;
};

// now register with Registry to instantiate the above
// reader/writer.
RegisterReaderWriterProxy<FLTReaderWriter> g_FLTReaderWriterProxy;

<|endoftext|>


<commit_before>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "stdafx.h"
#include "CppInterpreter.h"
#include "../CallResultImpl.h"
#include "../../StreamRedirector.h"
#ifndef USING_PRECOMPILED_HEADERS
#include "llvm_headers.h"
#include <sstream>
#endif

CppInterpreterParameters::retrieve_tls_f global_retrieve_tls = nullptr;
CppInterpreterParameters::store_tls_f global_store_tls_f = nullptr;

struct FailedToHash : public std::exception{
	std::string msg;
public:
	FailedToHash(const std::string &path){
		this->msg = "Unable to compute hash for \'" + path + "\'.";
	}
	const char *what() const noexcept override{
		return this->msg.c_str();
	}
};

CppInterpreter::CppInterpreter(const CppInterpreterParameters &parameters): parameters(parameters){
	global_retrieve_tls = this->parameters.retrieve_tls;
	global_store_tls_f = this->parameters.store_tls;
	auto params = this->parameters;
	this->hf = [params](const std::string &path) -> Sha1Sum{
		Sha1Sum ret;
		if (!params.get_file_sha1(params.state, path.c_str(), ret.data, sizeof(ret.data)))
			throw FailedToHash(path);
		return ret;
	};
}

CppInterpreter::~CppInterpreter(){

}

using namespace clang;
using namespace clang::driver;

static llvm::ExecutionEngine *create_execution_engine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr){
	return llvm::EngineBuilder(std::move(M))
		.setEngineKind(llvm::EngineKind::Either)
		.setErrorStr(ErrorStr)
		.create();
}

extern "C" __declspec(dllexport) void borderless_CppInterpreter_get_state(void **state, void **image){
	auto This = (CppInterpreter *)global_retrieve_tls(nullptr);
	This->pass_main_arguments(*state, *image);
}

extern "C" __declspec(dllexport) void borderless_CppInterpreter_return_result(void *return_value){
	auto This = (CppInterpreter *)global_retrieve_tls(nullptr);
	This->set_return_value(return_value);
}

bool execute(llvm::Module &mod, llvm::ExecutionEngine &execution_engine, CppInterpreter &cpp, std::string &error_message){
	llvm::Function *EntryFn = mod.getFunction("__borderless_main");
	if (!EntryFn){
		error_message = "'__borderless_main' function not found in module.";
		return false;
	}

	ArrayRef<llvm::GenericValue> args;
	execution_engine.finalizeObject();

	global_store_tls_f(nullptr, &cpp);
	execution_engine.runFunction(EntryFn, args);

	cpp.display_return_value_in_current_window();

	return true;
}

void CppInterpreter::display_return_value_in_current_window(){
	this->parameters.display_in_current_window(this->parameters.state, this->return_value);

}

CallResult CppInterpreter::execute_path(const char *filename){
	{
		CallResult ret;
		if (this->attempt_cache_reuse(ret, filename))
			return ret;
	}

	std::string error_message;
	std::string redirection;
	while (true){
#if defined(WIN32) && defined(_CONSOLE) || !defined(WIN32)
		StdStreamRedirectionGuard guard(redirection);
#endif

		IntrusiveRefCntPtr<DiagnosticOptions> diagnostic_options = new DiagnosticOptions();
		TextDiagnosticPrinter *text_diagnostic_printer = new TextDiagnosticPrinter(llvm::errs(), &*diagnostic_options);

		IntrusiveRefCntPtr<DiagnosticIDs> diagnostic_ids(new DiagnosticIDs());
		DiagnosticsEngine diagnostics_engine(diagnostic_ids, &*diagnostic_options, text_diagnostic_printer);

		// Use ELF on windows for now.
		std::string TripleStr = llvm::sys::getProcessTriple();
		llvm::Triple triple(TripleStr);
		if (triple.isOSBinFormatCOFF())
			triple.setObjectFormat(llvm::Triple::COFF);

		Driver driver("driver", triple.str(), diagnostics_engine);
		driver.setTitle("clang interpreter");
		driver.setCheckInputsExist(false);

		// FIXME: This is a hack to try to force the driver to do something we can
		// recognize. We need to extend the driver library to support this use model
		// (basically, exactly one input, and the operation mode is hard wired).
		SmallVector<const char *, 16> args;
		args.push_back("clang");
		args.push_back(filename);
		args.push_back("-fsyntax-only");
		args.push_back("-fms-compatibility-version=19");
		args.push_back("-O3");
		std::unique_ptr<Compilation> C(driver.BuildCompilation(args));
		if (!C){
			error_message = "Error initializing compiler.";
			break;
		}

		// FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.

		// We expect to get back exactly one command job, if we didn't something
		// failed. Extract that job from the compilation.
		const driver::JobList &jobs = C->getJobs();
		auto jobs_size = jobs.size();
		if (jobs_size != 1 || !isa<driver::Command>(*jobs.begin())) {
			SmallString<256> Msg;
			llvm::raw_svector_ostream OS(Msg);
			jobs.Print(OS, "; ", true);
			//Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
			error_message = OS.str();
			break;
		}

		const driver::Command &command = cast<driver::Command>(*jobs.begin());
		if (llvm::StringRef(command.getCreator().getName()) != "clang") {
			//Diags.Report(diag::err_fe_expected_clang_command);
			error_message = "Expected clang command.";
			break;
		}

		// Initialize a compiler invocation object from the clang (-cc1) arguments.
		const driver::ArgStringList &ccargs = command.getArguments();
		std::unique_ptr<CompilerInvocation> invocation(new CompilerInvocation);
		CompilerInvocation::CreateFromArgs(
			*invocation,
			const_cast<const char **>(ccargs.data()),
			const_cast<const char **>(ccargs.data()) + ccargs.size(),
			diagnostics_engine
		);

		// FIXME: This is copied from cc1_main.cpp; simplify and eliminate.

		// Create a compiler instance to handle the actual work.
		CompilerInstance clang;
		clang.setInvocation(invocation.release());

		// Create the compilers actual diagnostics engine.
		clang.createDiagnostics();
		if (!clang.hasDiagnostics()){
			error_message = "No diagnostics.";
			break;
		}

		// Create and execute the frontend to generate an LLVM bitcode module.
		std::shared_ptr<llvm::LLVMContext> context(new llvm::LLVMContext);
		std::unique_ptr<CodeGenAction> action(new EmitLLVMOnlyAction(context.get()));
		if (!clang.ExecuteAction(*action)){
			error_message = "Code generation failed.";
			break;
		}

		std::unique_ptr<llvm::Module> module = action->takeModule();
		if (!module){
			error_message = "No module generated.";
			break;
		}

		auto mod = module.get();

		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		std::shared_ptr<llvm::ExecutionEngine> execution_engine(create_execution_engine(std::move(module), &error_message));

		if (!execution_engine){
			error_message = "Unable to make execution engine: " + error_message;
			break;
		}

		if (!execute(*mod, *execution_engine, *this, error_message))
			break;

		this->save_in_cache(filename, context, execution_engine, mod);

		return CallResult();
	}

	CallResult ret;
	ret.impl = new CallResultImpl(redirection + "\n\n" + error_message);
	ret.success = false;
	ret.error_message = ret.impl->message.c_str();
	return ret;
}

void CppInterpreter::pass_main_arguments(void *&state, void *&image) const{
	state = this->parameters.state;
	image = this->parameters.caller_image;
}

bool CppInterpreter::attempt_cache_reuse(CallResult &result, const char *path){
	std::string spath = path;
	auto it = this->cached_programs.find(spath);
	if (it == this->cached_programs.end())
		return false;
	auto &program = *it->second;
	if (!program.equals(path)){
		this->cached_programs.erase(it);
		return false;
	}
	result = program.execute();
	return true;
}

void CppInterpreter::save_in_cache(const char *path, const std::shared_ptr<llvm::LLVMContext> &context, const std::shared_ptr<llvm::ExecutionEngine> &execution_engine, llvm::Module *module){
	std::string spath = path;
	this->cached_programs[spath].reset(new CachedProgram(this, spath, context, execution_engine, module));
}

CachedProgram::CachedProgram(
		CppInterpreter *interpreter,
		const std::string &path,
		const std::shared_ptr<llvm::LLVMContext> &context,
		const std::shared_ptr<llvm::ExecutionEngine> &execution_engine,
		llvm::Module *module
){
	this->interpreter = interpreter;
	this->path = path;
	this->context = context;
	this->execution_engine = execution_engine;
	this->module = module;
	this->hash = (*this->interpreter->get_hash_function())(this->path);
}

CallResult CachedProgram::execute(){
	std::string error_message;
	CallResult ret;
	if (::execute(*this->module, *this->execution_engine, *this->interpreter, error_message))
		return ret;
	ret.impl = new CallResultImpl(error_message);
	ret.success = false;
	ret.error_message = ret.impl->message.c_str();
	return ret;
}

bool CachedProgram::equals(const std::string &path){
	return (*this->interpreter->get_hash_function())(path) == this->hash;
}
<commit_msg>Minor stylistic changes.<commit_after>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "stdafx.h"
#include "CppInterpreter.h"
#include "../CallResultImpl.h"
#include "../../StreamRedirector.h"
#ifndef USING_PRECOMPILED_HEADERS
#include "llvm_headers.h"
#include <sstream>
#endif

CppInterpreterParameters::retrieve_tls_f global_retrieve_tls = nullptr;
CppInterpreterParameters::store_tls_f global_store_tls_f = nullptr;

struct FailedToHash : public std::exception{
	std::string msg;
public:
	FailedToHash(const std::string &path){
		this->msg = "Unable to compute hash for \'" + path + "\'.";
	}
	const char *what() const noexcept override{
		return this->msg.c_str();
	}
};

CppInterpreter::CppInterpreter(const CppInterpreterParameters &parameters): parameters(parameters){
	global_retrieve_tls = this->parameters.retrieve_tls;
	global_store_tls_f = this->parameters.store_tls;
	auto params = this->parameters;
	this->hf = [params](const std::string &path) -> Sha1Sum{
		Sha1Sum ret;
		if (!params.get_file_sha1(params.state, path.c_str(), ret.data, sizeof(ret.data)))
			throw FailedToHash(path);
		return ret;
	};
}

CppInterpreter::~CppInterpreter(){

}

using namespace clang;
using namespace clang::driver;

static llvm::ExecutionEngine *create_execution_engine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr){
	return llvm::EngineBuilder(std::move(M))
		.setEngineKind(llvm::EngineKind::Either)
		.setErrorStr(ErrorStr)
		.create();
}

extern "C" __declspec(dllexport) void borderless_CppInterpreter_get_state(void **state, void **image){
	auto This = (CppInterpreter *)global_retrieve_tls(nullptr);
	This->pass_main_arguments(*state, *image);
}

extern "C" __declspec(dllexport) void borderless_CppInterpreter_return_result(void *return_value){
	auto This = (CppInterpreter *)global_retrieve_tls(nullptr);
	This->set_return_value(return_value);
}

bool execute(llvm::Module &mod, llvm::ExecutionEngine &execution_engine, CppInterpreter &cpp, std::string &error_message){
	llvm::Function *EntryFn = mod.getFunction("__borderless_main");
	if (!EntryFn){
		error_message = "'__borderless_main' function not found in module.";
		return false;
	}

	ArrayRef<llvm::GenericValue> args;
	execution_engine.finalizeObject();

	global_store_tls_f(nullptr, &cpp);
	execution_engine.runFunction(EntryFn, args);

	cpp.display_return_value_in_current_window();

	return true;
}

void CppInterpreter::display_return_value_in_current_window(){
	this->parameters.display_in_current_window(this->parameters.state, this->return_value);

}

CallResult CppInterpreter::execute_path(const char *filename){
	{
		CallResult ret;
		if (this->attempt_cache_reuse(ret, filename))
			return ret;
	}

	std::string error_message;
	std::string redirection;
	while (true){
#if defined(WIN32) && defined(_CONSOLE) || !defined(WIN32)
		StdStreamRedirectionGuard guard(redirection);
#endif

		IntrusiveRefCntPtr<DiagnosticOptions> diagnostic_options = new DiagnosticOptions();

		IntrusiveRefCntPtr<DiagnosticIDs> diagnostic_ids = new DiagnosticIDs();
		DiagnosticsEngine diagnostics_engine(diagnostic_ids, &*diagnostic_options, new TextDiagnosticPrinter(llvm::errs(), &*diagnostic_options));

		// Use ELF on windows for now.
		std::string TripleStr = llvm::sys::getProcessTriple();
		llvm::Triple triple(TripleStr);
		if (triple.isOSBinFormatCOFF())
			triple.setObjectFormat(llvm::Triple::COFF);

		Driver driver("driver", triple.str(), diagnostics_engine);
		driver.setTitle("clang interpreter");
		driver.setCheckInputsExist(false);

		// FIXME: This is a hack to try to force the driver to do something we can
		// recognize. We need to extend the driver library to support this use model
		// (basically, exactly one input, and the operation mode is hard wired).
		SmallVector<const char *, 16> args;
		args.push_back("clang");
		args.push_back(filename);
		args.push_back("-fsyntax-only");
		args.push_back("-fms-compatibility-version=19");
		args.push_back("-O3");
		std::unique_ptr<Compilation> C(driver.BuildCompilation(args));
		if (!C){
			error_message = "Error initializing compiler.";
			break;
		}

		// FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.

		// We expect to get back exactly one command job, if we didn't something
		// failed. Extract that job from the compilation.
		const driver::JobList &jobs = C->getJobs();
		auto jobs_size = jobs.size();
		if (jobs_size != 1 || !isa<driver::Command>(*jobs.begin())) {
			SmallString<256> Msg;
			llvm::raw_svector_ostream OS(Msg);
			jobs.Print(OS, "; ", true);
			//Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
			error_message = OS.str();
			break;
		}

		const driver::Command &command = cast<driver::Command>(*jobs.begin());
		if (llvm::StringRef(command.getCreator().getName()) != "clang") {
			//Diags.Report(diag::err_fe_expected_clang_command);
			error_message = "Expected clang command.";
			break;
		}

		// Initialize a compiler invocation object from the clang (-cc1) arguments.
		const driver::ArgStringList &ccargs = command.getArguments();
		auto invocation = std::make_unique<CompilerInvocation>();
		CompilerInvocation::CreateFromArgs(
			*invocation,
			const_cast<const char **>(ccargs.data()),
			const_cast<const char **>(ccargs.data()) + ccargs.size(),
			diagnostics_engine
		);

		// FIXME: This is copied from cc1_main.cpp; simplify and eliminate.

		// Create a compiler instance to handle the actual work.
		CompilerInstance clang;
		clang.setInvocation(invocation.release());

		// Create the compilers actual diagnostics engine.
		clang.createDiagnostics();
		if (!clang.hasDiagnostics()){
			error_message = "No diagnostics.";
			break;
		}

		// Create and execute the frontend to generate an LLVM bitcode module.
		auto context = std::make_shared<llvm::LLVMContext>();
		auto action = std::make_unique<EmitLLVMOnlyAction>(context.get());
		if (!clang.ExecuteAction(*action)){
			error_message = "Code generation failed.";
			break;
		}

		auto module = action->takeModule();
		if (!module){
			error_message = "No module generated.";
			break;
		}

		auto mod = module.get();

		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		std::shared_ptr<llvm::ExecutionEngine> execution_engine(create_execution_engine(std::move(module), &error_message));

		if (!execution_engine){
			error_message = "Unable to make execution engine: " + error_message;
			break;
		}

		if (!execute(*mod, *execution_engine, *this, error_message))
			break;

		this->save_in_cache(filename, context, execution_engine, mod);

		return CallResult();
	}

	CallResult ret;
	ret.impl = new CallResultImpl(redirection + "\n\n" + error_message);
	ret.success = false;
	ret.error_message = ret.impl->message.c_str();
	return ret;
}

void CppInterpreter::pass_main_arguments(void *&state, void *&image) const{
	state = this->parameters.state;
	image = this->parameters.caller_image;
}

bool CppInterpreter::attempt_cache_reuse(CallResult &result, const char *path){
	std::string spath = path;
	auto it = this->cached_programs.find(spath);
	if (it == this->cached_programs.end())
		return false;
	auto &program = *it->second;
	if (!program.equals(path)){
		this->cached_programs.erase(it);
		return false;
	}
	result = program.execute();
	return true;
}

void CppInterpreter::save_in_cache(const char *path, const std::shared_ptr<llvm::LLVMContext> &context, const std::shared_ptr<llvm::ExecutionEngine> &execution_engine, llvm::Module *module){
	std::string spath = path;
	this->cached_programs[spath].reset(new CachedProgram(this, spath, context, execution_engine, module));
}

CachedProgram::CachedProgram(
		CppInterpreter *interpreter,
		const std::string &path,
		const std::shared_ptr<llvm::LLVMContext> &context,
		const std::shared_ptr<llvm::ExecutionEngine> &execution_engine,
		llvm::Module *module
){
	this->interpreter = interpreter;
	this->path = path;
	this->context = context;
	this->execution_engine = execution_engine;
	this->module = module;
	this->hash = (*this->interpreter->get_hash_function())(this->path);
}

CallResult CachedProgram::execute(){
	std::string error_message;
	CallResult ret;
	if (::execute(*this->module, *this->execution_engine, *this->interpreter, error_message))
		return ret;
	ret.impl = new CallResultImpl(error_message);
	ret.success = false;
	ret.error_message = ret.impl->message.c_str();
	return ret;
}

bool CachedProgram::equals(const std::string &path){
	return (*this->interpreter->get_hash_function())(path) == this->hash;
}
<|endoftext|>


<commit_before>/* Copyright 2017 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "src/quota_operation_aggregator.h"

#include <unordered_map>

#include "gmock/gmock.h"
#include "google/protobuf/text_format.h"
#include "google/protobuf/util/message_differencer.h"
#include "gtest/gtest.h"
#include "utils/status_test_util.h"

#include <unistd.h>

using std::string;
using ::google::api::servicecontrol::v1::QuotaOperation;
using ::google::protobuf::TextFormat;
using ::google::protobuf::util::MessageDifferencer;
using ::google::protobuf::util::Status;
using ::google::protobuf::util::StatusCode;

namespace google {
namespace service_control_client {
namespace {

const char kOperation1[] = R"(
operation_id: "operationid"
method_name: "methodname"
consumer_id: "consumerid"
quota_metrics {
  metric_name: "metric_first"
  metric_values {
    int64_value: 1
  }
}
quota_metrics {
  metric_name: "metric_second"
  metric_values {
    int64_value: 1
  }
}
quota_mode: BEST_EFFORT
)";

const char kOperation2[] = R"(
operation_id: "operationid"
method_name: "methodname"
consumer_id: "consumerid"
quota_metrics {
  metric_name: "metric_first"
  metric_values {
    int64_value: 2
  }
}
quota_metrics {
  metric_name: "metric_second"
  metric_values {
    int64_value: 3
  }
}
quota_mode: BEST_EFFORT
)";

const std::set<std::pair<std::string, int>> ExtractMetricSets(
    const ::google::api::servicecontrol::v1::QuotaOperation& operation) {
  std::set<std::pair<std::string, int>> sets;

  for (auto quota_metric : operation.quota_metrics()) {
    sets.insert(std::make_pair(quota_metric.metric_name(),
                               quota_metric.metric_values(0).int64_value()));
  }

  return sets;
}

}  // namespace

class QuotaOperationAggregatorImplTest : public ::testing::Test {
 public:
  void SetUp() {
    ASSERT_TRUE(TextFormat::ParseFromString(kOperation1, &operation1_));
    ASSERT_TRUE(TextFormat::ParseFromString(kOperation2, &operation2_));
  }

  ::google::api::servicecontrol::v1::QuotaOperation operation1_;
  ::google::api::servicecontrol::v1::QuotaOperation operation2_;
};

TEST_F(QuotaOperationAggregatorImplTest, TestInitialization) {
  QuotaOperationAggregator aggregator(operation1_);

  QuotaOperation operation = aggregator.ToOperationProto();

  std::set<std::pair<std::string, int>> quota_metrics =
      ExtractMetricSets(operation);
  std::set<std::pair<std::string, int>> expected_costs = {{"metric_first", 1},
                                                          {"metric_second", 1}};
  ASSERT_EQ(quota_metrics, expected_costs);
}

TEST_F(QuotaOperationAggregatorImplTest, TestMergeOperation) {
  QuotaOperationAggregator aggregator(operation1_);

  aggregator.MergeOperation(operation2_);

  QuotaOperation operation = aggregator.ToOperationProto();
  std::set<std::pair<std::string, int>> quota_metrics =
      ExtractMetricSets(operation);
  std::set<std::pair<std::string, int>> expected_costs = {{"metric_first", 3},
                                                          {"metric_second", 4}};
  ASSERT_EQ(quota_metrics, expected_costs);
}

}  // namespace service_control_client
}  // namespace google
<commit_msg>removed un-used using abls::Status (#46)<commit_after>/* Copyright 2017 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "src/quota_operation_aggregator.h"

#include <unordered_map>

#include "gmock/gmock.h"
#include "google/protobuf/text_format.h"
#include "google/protobuf/util/message_differencer.h"
#include "gtest/gtest.h"
#include "utils/status_test_util.h"

#include <unistd.h>

using std::string;
using ::google::api::servicecontrol::v1::QuotaOperation;
using ::google::protobuf::TextFormat;
using ::google::protobuf::util::MessageDifferencer;

namespace google {
namespace service_control_client {
namespace {

const char kOperation1[] = R"(
operation_id: "operationid"
method_name: "methodname"
consumer_id: "consumerid"
quota_metrics {
  metric_name: "metric_first"
  metric_values {
    int64_value: 1
  }
}
quota_metrics {
  metric_name: "metric_second"
  metric_values {
    int64_value: 1
  }
}
quota_mode: BEST_EFFORT
)";

const char kOperation2[] = R"(
operation_id: "operationid"
method_name: "methodname"
consumer_id: "consumerid"
quota_metrics {
  metric_name: "metric_first"
  metric_values {
    int64_value: 2
  }
}
quota_metrics {
  metric_name: "metric_second"
  metric_values {
    int64_value: 3
  }
}
quota_mode: BEST_EFFORT
)";

const std::set<std::pair<std::string, int>> ExtractMetricSets(
    const ::google::api::servicecontrol::v1::QuotaOperation& operation) {
  std::set<std::pair<std::string, int>> sets;

  for (auto quota_metric : operation.quota_metrics()) {
    sets.insert(std::make_pair(quota_metric.metric_name(),
                               quota_metric.metric_values(0).int64_value()));
  }

  return sets;
}

}  // namespace

class QuotaOperationAggregatorImplTest : public ::testing::Test {
 public:
  void SetUp() {
    ASSERT_TRUE(TextFormat::ParseFromString(kOperation1, &operation1_));
    ASSERT_TRUE(TextFormat::ParseFromString(kOperation2, &operation2_));
  }

  ::google::api::servicecontrol::v1::QuotaOperation operation1_;
  ::google::api::servicecontrol::v1::QuotaOperation operation2_;
};

TEST_F(QuotaOperationAggregatorImplTest, TestInitialization) {
  QuotaOperationAggregator aggregator(operation1_);

  QuotaOperation operation = aggregator.ToOperationProto();

  std::set<std::pair<std::string, int>> quota_metrics =
      ExtractMetricSets(operation);
  std::set<std::pair<std::string, int>> expected_costs = {{"metric_first", 1},
                                                          {"metric_second", 1}};
  ASSERT_EQ(quota_metrics, expected_costs);
}

TEST_F(QuotaOperationAggregatorImplTest, TestMergeOperation) {
  QuotaOperationAggregator aggregator(operation1_);

  aggregator.MergeOperation(operation2_);

  QuotaOperation operation = aggregator.ToOperationProto();
  std::set<std::pair<std::string, int>> quota_metrics =
      ExtractMetricSets(operation);
  std::set<std::pair<std::string, int>> expected_costs = {{"metric_first", 3},
                                                          {"metric_second", 4}};
  ASSERT_EQ(quota_metrics, expected_costs);
}

}  // namespace service_control_client
}  // namespace google
<|endoftext|>


<commit_before>#include "boost_test.h"
#include "ComplexFixedPoint.h"
#include "FixedPoint.h"
#include <complex>

using namespace std;

BOOST_AUTO_TEST_CASE( CFxpConstructors )
{
	/* Check constructors */
	CFxp b(1, -3, 4, 1);
	BOOST_CHECK_EQUAL(b.width(), 4);
	BOOST_CHECK_EQUAL(b.fracBits(), 1);
	BOOST_CHECK_EQUAL(b.real(), 1);
	BOOST_CHECK_EQUAL(b.imag(), -3);
	CFxp c(complex<int64_t>(5, -13), 6, 3);
	BOOST_CHECK_EQUAL(c.width(), 6);
	BOOST_CHECK_EQUAL(c.fracBits(), 3);
	BOOST_CHECK_EQUAL(c.real(), 5);
	BOOST_CHECK_EQUAL(c.imag(), -13);

	/* Values too large for width */
	BOOST_CHECK_THROW(CFxp(128, 0, 8), range_error);
	BOOST_CHECK_THROW(CFxp(0, -129, 8), range_error);

	/* Width larger than max allowed width */
	BOOST_CHECK_THROW(CFxp(0, 0, CFxp::MAX_WIDTH + 1), range_error);

	/* More fractional bits than total bits */
	BOOST_CHECK_THROW(CFxp(0, 0, 2, 3), range_error);
}

BOOST_AUTO_TEST_CASE( CFxpQuantize )
{
	complex<double> a(2.34, -6.98);
	complex<float> c(4.982, 9.12294847);

	/* Normal quantization */
	CFxp b = CFxp::quantize(a, 12, 4);
	BOOST_CHECK_EQUAL(b.real(), 37);
	BOOST_CHECK_EQUAL(b.imag(), -112);
	BOOST_CHECK_EQUAL(b.width(), 12);
	BOOST_CHECK_EQUAL(b.fracBits(), 4);
	BOOST_CHECK_CLOSE(b.toDouble().real(), 2.3125, 0.001);
	BOOST_CHECK_CLOSE(b.toDouble().imag(), -7.0, 0.001);

	/* Try to quantize with too few integer bits */
	BOOST_CHECK_THROW(CFxp::quantize(a, 12, 10), range_error);
}

BOOST_AUTO_TEST_CASE( CFxpAccessors )
{
	CFxp a(1, 2, 8, 3);

	BOOST_CHECK_EQUAL(a.real(), 1);
	BOOST_CHECK_EQUAL(a.imag(), 2);
	BOOST_CHECK_EQUAL(a.width(), 8);
	BOOST_CHECK_EQUAL(a.fracBits(), 3);
	BOOST_CHECK_EQUAL(a.minVal(), -128);
	BOOST_CHECK_EQUAL(a.maxVal(), 127);
	BOOST_CHECK_EQUAL(a.maxHeldVal(), 2);
	BOOST_CHECK_EQUAL(a.minHeldVal(), 1);
	a = CFxp(123, -116, 8, 3);
	BOOST_CHECK_EQUAL(a.maxHeldVal(), 123);
	BOOST_CHECK_EQUAL(a.minHeldVal(), -116);

}

BOOST_AUTO_TEST_CASE( CFxpAssignment )
{
	CFxp a(1, 2, 8);
	CFxp b(1, 2, 10);
	CFxp c(0, 0, 8);
	CFxp d(1, 2, 8, 3);

	/* lhs and rhs widths must match by default */
	BOOST_CHECK_THROW(a = b, runtime_error);

	/* lhs and rhs binary point must be in same position */
	BOOST_CHECK_THROW(a = d, runtime_error);

	/* Valid assignment */
	BOOST_CHECK_NO_THROW(c = a);
	BOOST_CHECK_EQUAL(c, a);
}

BOOST_AUTO_TEST_CASE( CFxpEquality )
{
	CFxp a(1, 2, 8, 3);
	CFxp b(1, 2, 8, 3);
	CFxp c(1, 2, 10, 3);
	CFxp d(13, 2, 8, 3);
	CFxp e(1, 13, 8, 3);
	CFxp f(1, 2, 8, 1);
	CFxp g(24, 38, 21, 7);

	/* same object as lhs and rhs */
	BOOST_CHECK_EQUAL(a == a, true);
	BOOST_CHECK_EQUAL(a != a, false);

	/* different equal objects */
	BOOST_CHECK_EQUAL(a == b, true);
	BOOST_CHECK_EQUAL(a != b, false);

	/* same value, different widths */
	BOOST_CHECK_EQUAL(a == c, false);
	BOOST_CHECK_EQUAL(a != c, true);

	/* different values, same widths */
	BOOST_CHECK_EQUAL(a == d, false);
	BOOST_CHECK_EQUAL(a != d, true);
	BOOST_CHECK_EQUAL(a == e, false);
	BOOST_CHECK_EQUAL(a != e, true);

	/* same value, same size, different number of fractional bits */
	BOOST_CHECK_EQUAL(a == f, false);
	BOOST_CHECK_EQUAL(a != f, true);

	/* everything different */
	BOOST_CHECK_EQUAL(a == g, false);
	BOOST_CHECK_EQUAL(a != g, true);
}

BOOST_AUTO_TEST_CASE( CFxpAddition )
{
	CFxp a(1, 2, 8);
	CFxp b(2, 5, 5);
	CFxp c(4, 12, 8, 3);

	/* addition is commutative */
	BOOST_CHECK_EQUAL(a + b, b + a);

	/* chaining works */
	BOOST_CHECK_EQUAL(a + a + a, a + a + a);

	/* width after addition */
	BOOST_CHECK_EQUAL((a + b).width(), 9);

	/* result check */
	BOOST_CHECK_EQUAL(a + b, CFxp(3, 7, 9));

	/* different number of fractional bits */
	CFxp d = a + c;
	BOOST_CHECK_EQUAL(d.width(), 12);
	BOOST_CHECK_EQUAL(d.fracBits(), 3);
	BOOST_CHECK_EQUAL(d, CFxp(12, 28, 12, 3));
	d = c + a;
	BOOST_CHECK_EQUAL(d.width(), 12);
	BOOST_CHECK_EQUAL(d.fracBits(), 3);
	BOOST_CHECK_EQUAL(d, CFxp(12, 28, 12, 3));
}

BOOST_AUTO_TEST_CASE( CFxpScalarMultiplication )
{
	CFxp a(1, 2, 8, 1);
	Fxp b(2, 5, 3);

	/* multiplication by scalar is commutative */
	BOOST_CHECK_EQUAL(a * b, b * a);

	/* width after multiplication by scalar */
	BOOST_CHECK_EQUAL((a * b).width(), 13);

	/* result check */
	BOOST_CHECK_EQUAL(a * b, CFxp(2, 4, 13, 4));
}

BOOST_AUTO_TEST_CASE( CFxpMultiplication )
{
	CFxp a(1, 2, 8);
	CFxp b(2, 5, 5);
	CFxp c(4, 12, 8, 3);
	CFxp d(3, -7, 6, 1);

	/* complex multiplication is commutative */
	BOOST_CHECK_EQUAL(a * b, b * a);

	/* chaining works */
	BOOST_CHECK_EQUAL(a * a * a, a * a * a);

	/* width after multiplication */
	BOOST_CHECK_EQUAL((a * b).width(), 14);

	/* result check */
	BOOST_CHECK_EQUAL(a * b, CFxp(-8, 9, 14));

	/* handling of fractional bits */
	CFxp e = c * d;
	BOOST_CHECK_EQUAL(e.width(), 15);
	BOOST_CHECK_EQUAL(e.fracBits(), 4);
	BOOST_CHECK_EQUAL(e, CFxp(96, 8, 15, 4));
	e = d * c;
	BOOST_CHECK_EQUAL(e.width(), 15);
	BOOST_CHECK_EQUAL(e.fracBits(), 4);
	BOOST_CHECK_EQUAL(e, CFxp(96, 8, 15, 4));
}

BOOST_AUTO_TEST_CASE( CFxpTruncation )
{
	CFxp a(15, -32, 10, 2);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.truncateBy(2), CFxp(3, -8, 8, 0));
	BOOST_CHECK_EQUAL(a.truncateTo(7), CFxp(1, -4, 7, 0));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.truncateTo(0), std::range_error);
	BOOST_CHECK_THROW(a.truncateBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpSaturation )
{
	CFxp a(432, -397, 10);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.saturateBy(2), CFxp(127, -128, 8));
	BOOST_CHECK_EQUAL(a.saturateTo(6), CFxp(31, -32, 6));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.saturateTo(0), std::range_error);
	BOOST_CHECK_THROW(a.saturateBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpRounding )
{
	CFxp a(15, -32, 10, 2);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.roundBy(2), CFxp(4, -8, 8, 0));
	BOOST_CHECK_EQUAL(a.roundTo(7), CFxp(2, -4, 7, 0));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.roundTo(0), std::range_error);
	BOOST_CHECK_THROW(a.roundBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpSignExtension )
{
	CFxp a(15, -32, 10);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.signExtendBy(2), CFxp(15, -32, 12));
	BOOST_CHECK_EQUAL(a.signExtendTo(51), CFxp(15, -32, 51));

	/* Try to sign extend beyond allowed range */
	BOOST_CHECK_THROW(a.signExtendTo(CFxp::MAX_WIDTH + 1), std::range_error);
	BOOST_CHECK_THROW(a.signExtendBy(CFxp::MAX_WIDTH - a.width() + 1), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpToFloat )
{
	/* check a simple case */
	CFxp a(15, -32, 10, 1);
	BOOST_CHECK_CLOSE(a.toFloat().real(), 15.0/2.0, 0.001);
	BOOST_CHECK_CLOSE(a.toFloat().imag(), -32.0/2.0, 0.001);

	/* check an extreme case */
	CFxp b(15, -32, 64, 64);
	BOOST_CHECK_CLOSE(b.toFloat().real(), 15.0/pow(2.0, 64.0), 0.001);
	BOOST_CHECK_CLOSE(b.toFloat().imag(), -32.0/pow(2.0, 64.0), 0.001);
}

BOOST_AUTO_TEST_CASE( CFxpToDouble )
{
	/* check a simple case */
	CFxp a(15, -32, 10, 1);
	BOOST_CHECK_CLOSE(a.toDouble().real(), 15.0/2.0, 0.001);
	BOOST_CHECK_CLOSE(a.toDouble().imag(), -32.0/2.0, 0.001);

	/* check an extreme case */
	CFxp b(15, -32, 64, 64);
	BOOST_CHECK_CLOSE(b.toDouble().real(), 15.0/pow(2.0, 64.0), 0.001);
	BOOST_CHECK_CLOSE(b.toDouble().imag(), -32.0/pow(2.0, 64.0), 0.001);
}
<commit_msg>CFxp: Removed unused variable from quantize unit test<commit_after>#include "boost_test.h"
#include "ComplexFixedPoint.h"
#include "FixedPoint.h"
#include <complex>

using namespace std;

BOOST_AUTO_TEST_CASE( CFxpConstructors )
{
	/* Check constructors */
	CFxp b(1, -3, 4, 1);
	BOOST_CHECK_EQUAL(b.width(), 4);
	BOOST_CHECK_EQUAL(b.fracBits(), 1);
	BOOST_CHECK_EQUAL(b.real(), 1);
	BOOST_CHECK_EQUAL(b.imag(), -3);
	CFxp c(complex<int64_t>(5, -13), 6, 3);
	BOOST_CHECK_EQUAL(c.width(), 6);
	BOOST_CHECK_EQUAL(c.fracBits(), 3);
	BOOST_CHECK_EQUAL(c.real(), 5);
	BOOST_CHECK_EQUAL(c.imag(), -13);

	/* Values too large for width */
	BOOST_CHECK_THROW(CFxp(128, 0, 8), range_error);
	BOOST_CHECK_THROW(CFxp(0, -129, 8), range_error);

	/* Width larger than max allowed width */
	BOOST_CHECK_THROW(CFxp(0, 0, CFxp::MAX_WIDTH + 1), range_error);

	/* More fractional bits than total bits */
	BOOST_CHECK_THROW(CFxp(0, 0, 2, 3), range_error);
}

BOOST_AUTO_TEST_CASE( CFxpQuantize )
{
	complex<double> a(2.34, -6.98);

	/* Normal quantization */
	CFxp b = CFxp::quantize(a, 12, 4);
	BOOST_CHECK_EQUAL(b.real(), 37);
	BOOST_CHECK_EQUAL(b.imag(), -112);
	BOOST_CHECK_EQUAL(b.width(), 12);
	BOOST_CHECK_EQUAL(b.fracBits(), 4);
	BOOST_CHECK_CLOSE(b.toDouble().real(), 2.3125, 0.001);
	BOOST_CHECK_CLOSE(b.toDouble().imag(), -7.0, 0.001);

	/* Try to quantize with too few integer bits */
	BOOST_CHECK_THROW(CFxp::quantize(a, 12, 10), range_error);
}

BOOST_AUTO_TEST_CASE( CFxpAccessors )
{
	CFxp a(1, 2, 8, 3);

	BOOST_CHECK_EQUAL(a.real(), 1);
	BOOST_CHECK_EQUAL(a.imag(), 2);
	BOOST_CHECK_EQUAL(a.width(), 8);
	BOOST_CHECK_EQUAL(a.fracBits(), 3);
	BOOST_CHECK_EQUAL(a.minVal(), -128);
	BOOST_CHECK_EQUAL(a.maxVal(), 127);
	BOOST_CHECK_EQUAL(a.maxHeldVal(), 2);
	BOOST_CHECK_EQUAL(a.minHeldVal(), 1);
	a = CFxp(123, -116, 8, 3);
	BOOST_CHECK_EQUAL(a.maxHeldVal(), 123);
	BOOST_CHECK_EQUAL(a.minHeldVal(), -116);

}

BOOST_AUTO_TEST_CASE( CFxpAssignment )
{
	CFxp a(1, 2, 8);
	CFxp b(1, 2, 10);
	CFxp c(0, 0, 8);
	CFxp d(1, 2, 8, 3);

	/* lhs and rhs widths must match by default */
	BOOST_CHECK_THROW(a = b, runtime_error);

	/* lhs and rhs binary point must be in same position */
	BOOST_CHECK_THROW(a = d, runtime_error);

	/* Valid assignment */
	BOOST_CHECK_NO_THROW(c = a);
	BOOST_CHECK_EQUAL(c, a);
}

BOOST_AUTO_TEST_CASE( CFxpEquality )
{
	CFxp a(1, 2, 8, 3);
	CFxp b(1, 2, 8, 3);
	CFxp c(1, 2, 10, 3);
	CFxp d(13, 2, 8, 3);
	CFxp e(1, 13, 8, 3);
	CFxp f(1, 2, 8, 1);
	CFxp g(24, 38, 21, 7);

	/* same object as lhs and rhs */
	BOOST_CHECK_EQUAL(a == a, true);
	BOOST_CHECK_EQUAL(a != a, false);

	/* different equal objects */
	BOOST_CHECK_EQUAL(a == b, true);
	BOOST_CHECK_EQUAL(a != b, false);

	/* same value, different widths */
	BOOST_CHECK_EQUAL(a == c, false);
	BOOST_CHECK_EQUAL(a != c, true);

	/* different values, same widths */
	BOOST_CHECK_EQUAL(a == d, false);
	BOOST_CHECK_EQUAL(a != d, true);
	BOOST_CHECK_EQUAL(a == e, false);
	BOOST_CHECK_EQUAL(a != e, true);

	/* same value, same size, different number of fractional bits */
	BOOST_CHECK_EQUAL(a == f, false);
	BOOST_CHECK_EQUAL(a != f, true);

	/* everything different */
	BOOST_CHECK_EQUAL(a == g, false);
	BOOST_CHECK_EQUAL(a != g, true);
}

BOOST_AUTO_TEST_CASE( CFxpAddition )
{
	CFxp a(1, 2, 8);
	CFxp b(2, 5, 5);
	CFxp c(4, 12, 8, 3);

	/* addition is commutative */
	BOOST_CHECK_EQUAL(a + b, b + a);

	/* chaining works */
	BOOST_CHECK_EQUAL(a + a + a, a + a + a);

	/* width after addition */
	BOOST_CHECK_EQUAL((a + b).width(), 9);

	/* result check */
	BOOST_CHECK_EQUAL(a + b, CFxp(3, 7, 9));

	/* different number of fractional bits */
	CFxp d = a + c;
	BOOST_CHECK_EQUAL(d.width(), 12);
	BOOST_CHECK_EQUAL(d.fracBits(), 3);
	BOOST_CHECK_EQUAL(d, CFxp(12, 28, 12, 3));
	d = c + a;
	BOOST_CHECK_EQUAL(d.width(), 12);
	BOOST_CHECK_EQUAL(d.fracBits(), 3);
	BOOST_CHECK_EQUAL(d, CFxp(12, 28, 12, 3));
}

BOOST_AUTO_TEST_CASE( CFxpScalarMultiplication )
{
	CFxp a(1, 2, 8, 1);
	Fxp b(2, 5, 3);

	/* multiplication by scalar is commutative */
	BOOST_CHECK_EQUAL(a * b, b * a);

	/* width after multiplication by scalar */
	BOOST_CHECK_EQUAL((a * b).width(), 13);

	/* result check */
	BOOST_CHECK_EQUAL(a * b, CFxp(2, 4, 13, 4));
}

BOOST_AUTO_TEST_CASE( CFxpMultiplication )
{
	CFxp a(1, 2, 8);
	CFxp b(2, 5, 5);
	CFxp c(4, 12, 8, 3);
	CFxp d(3, -7, 6, 1);

	/* complex multiplication is commutative */
	BOOST_CHECK_EQUAL(a * b, b * a);

	/* chaining works */
	BOOST_CHECK_EQUAL(a * a * a, a * a * a);

	/* width after multiplication */
	BOOST_CHECK_EQUAL((a * b).width(), 14);

	/* result check */
	BOOST_CHECK_EQUAL(a * b, CFxp(-8, 9, 14));

	/* handling of fractional bits */
	CFxp e = c * d;
	BOOST_CHECK_EQUAL(e.width(), 15);
	BOOST_CHECK_EQUAL(e.fracBits(), 4);
	BOOST_CHECK_EQUAL(e, CFxp(96, 8, 15, 4));
	e = d * c;
	BOOST_CHECK_EQUAL(e.width(), 15);
	BOOST_CHECK_EQUAL(e.fracBits(), 4);
	BOOST_CHECK_EQUAL(e, CFxp(96, 8, 15, 4));
}

BOOST_AUTO_TEST_CASE( CFxpTruncation )
{
	CFxp a(15, -32, 10, 2);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.truncateBy(2), CFxp(3, -8, 8, 0));
	BOOST_CHECK_EQUAL(a.truncateTo(7), CFxp(1, -4, 7, 0));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.truncateTo(0), std::range_error);
	BOOST_CHECK_THROW(a.truncateBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpSaturation )
{
	CFxp a(432, -397, 10);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.saturateBy(2), CFxp(127, -128, 8));
	BOOST_CHECK_EQUAL(a.saturateTo(6), CFxp(31, -32, 6));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.saturateTo(0), std::range_error);
	BOOST_CHECK_THROW(a.saturateBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpRounding )
{
	CFxp a(15, -32, 10, 2);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.roundBy(2), CFxp(4, -8, 8, 0));
	BOOST_CHECK_EQUAL(a.roundTo(7), CFxp(2, -4, 7, 0));

	/* Go beyond allowed range */
	BOOST_CHECK_THROW(a.roundTo(0), std::range_error);
	BOOST_CHECK_THROW(a.roundBy(a.width()), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpSignExtension )
{
	CFxp a(15, -32, 10);

	/* Check results for normal use */
	BOOST_CHECK_EQUAL(a.signExtendBy(2), CFxp(15, -32, 12));
	BOOST_CHECK_EQUAL(a.signExtendTo(51), CFxp(15, -32, 51));

	/* Try to sign extend beyond allowed range */
	BOOST_CHECK_THROW(a.signExtendTo(CFxp::MAX_WIDTH + 1), std::range_error);
	BOOST_CHECK_THROW(a.signExtendBy(CFxp::MAX_WIDTH - a.width() + 1), std::range_error);
}

BOOST_AUTO_TEST_CASE( CFxpToFloat )
{
	/* check a simple case */
	CFxp a(15, -32, 10, 1);
	BOOST_CHECK_CLOSE(a.toFloat().real(), 15.0/2.0, 0.001);
	BOOST_CHECK_CLOSE(a.toFloat().imag(), -32.0/2.0, 0.001);

	/* check an extreme case */
	CFxp b(15, -32, 64, 64);
	BOOST_CHECK_CLOSE(b.toFloat().real(), 15.0/pow(2.0, 64.0), 0.001);
	BOOST_CHECK_CLOSE(b.toFloat().imag(), -32.0/pow(2.0, 64.0), 0.001);
}

BOOST_AUTO_TEST_CASE( CFxpToDouble )
{
	/* check a simple case */
	CFxp a(15, -32, 10, 1);
	BOOST_CHECK_CLOSE(a.toDouble().real(), 15.0/2.0, 0.001);
	BOOST_CHECK_CLOSE(a.toDouble().imag(), -32.0/2.0, 0.001);

	/* check an extreme case */
	CFxp b(15, -32, 64, 64);
	BOOST_CHECK_CLOSE(b.toDouble().real(), 15.0/pow(2.0, 64.0), 0.001);
	BOOST_CHECK_CLOSE(b.toDouble().imag(), -32.0/pow(2.0, 64.0), 0.001);
}
<|endoftext|>


<commit_before>#include "UnitTestUtils.h"
#include "LoopPathTestCase.h"

#include "mgl/loop_path.h"

#include <iostream>
#include <sstream>

using namespace std;
using namespace mgl;
using namespace libthing;

CPPUNIT_TEST_SUITE_REGISTRATION( LoopPathTestCase );

void LoopPathTestCase::setUp() {
	cout << endl << "No setup" << endl;
}

void LoopPathTestCase::testOpenPathBasic() {
	cout << "Testing basic OpenPath functionality" << endl;

	OpenPath path;

	path.appendPoint(Vector2(5, 5));
	OpenPath::iterator i = path.fromStart();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 5.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	++i;
	CPPUNIT_ASSERT(i == path.end());

	path.appendPoint(Vector2(5, 6));
	i = path.fromStart();
	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 5.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 6.0);

	++i;
	CPPUNIT_ASSERT(i == path.end());

	path.prependPoint(Vector2(6, 5));
	i = path.fromStart();
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	LineSegment2 seg = path.segmentAfterPoint(i);
	CPPUNIT_ASSERT_EQUAL(seg.length(), 1.0);

	OpenPath::entry_iterator entry = path.getEntryPoints();
	Vector2 first_entry = *entry;
	Vector2 start = *(path.fromStart());
	CPPUNIT_ASSERT_EQUAL(first_entry.x, start.x);
	CPPUNIT_ASSERT_EQUAL(first_entry.y, start.y);

	++entry;
	Vector2 second_entry = *entry;
	Vector2 end = *(path.fromEnd());
	CPPUNIT_ASSERT_EQUAL(second_entry.x, end.x);
	CPPUNIT_ASSERT_EQUAL(second_entry.y, end.y);

	Vector2 first_exit = path.getExitPoint(first_entry);
	CPPUNIT_ASSERT_EQUAL(first_exit.x, second_entry.x);
	CPPUNIT_ASSERT_EQUAL(first_exit.y, second_entry.y);

	Vector2 second_exit = path.getExitPoint(second_entry);
	CPPUNIT_ASSERT_EQUAL(second_exit.x, first_entry.x);
	CPPUNIT_ASSERT_EQUAL(second_exit.y, first_entry.y);
}

void LoopPathTestCase::testLoopBasic() {
	cout << "Testing single point loop" << endl;

	Loop loop(Vector2(2, 3));

	Loop::cw_iterator i = loop.clockwise();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 3.0);

	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 3.0);

	cout << "Testing two point loop" << endl;
	i = loop.insertPoint(Vector2(4, 5), i);
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	++i;
	second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 3.0);

	++i;
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	cout << "Testing three point loop" << endl;
	i = loop.insertPoint(Vector2(6, 7), i);
	Loop::ccw_iterator j = loop.counterClockwise(*i);
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 7.0);

	++i;
	second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 5.0);

	++i;
	Vector2 third = *i;
	CPPUNIT_ASSERT_EQUAL(third.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(third.y, 3.0);

	++i;
	Vector2 fourth = *i;
	CPPUNIT_ASSERT_EQUAL(fourth.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(fourth.y, 7.0);

	cout << "Testing segmentAfterPoint" << endl;
	LineSegment2 seg = loop.segmentAfterPoint(i);
	CPPUNIT_ASSERT_EQUAL(seg.squaredLength(), 8.0);

	cout << "Testing entry points" << endl;
	int count = 1;
	Loop::entry_iterator entry = loop.entryBegin();
	for (;	entry != loop.entryEnd(); entry++)
		count++;

	CPPUNIT_ASSERT_EQUAL(count, 3);

	Vector2 exitpoint = loop.getExitPoint(entry);
	Vector2 entrypoint = *entry;
	CPPUNIT_ASSERT_EQUAL(entrypoint.x, exitpoint.x);
	CPPUNIT_ASSERT_EQUAL(entrypoint.y, exitpoint.y);
}

void LoopPathTestCase::testLoopPathBasic() {
	Loop loop(Vector2(1, 2));

	Loop::cw_iterator last = loop.insertPoint(Vector2(3, 4), loop.clockwise());

	LoopPath lp(loop, loop.clockwise(Vector2(1, 2)),
			loop.counterClockwise(Vector2(1, 2)));

	LoopPath::iterator i = lp.fromStart();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 2.0);

	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 4.0);

	++i;
	bool res = i == lp.end();
	CPPUNIT_ASSERT(res);
}

void LoopPathTestCase::testOpenPathJoin() {
	OpenPath path1;
	path1.appendPoint(Vector2(1, 1));
	path1.appendPoint(Vector2(2, 2));

	OpenPath path2;
	path2.appendPoint(Vector2(3, 3));
	path2.appendPoint(Vector2(4, 4));

	OpenPath joined;
	joined.appendPoints(path1.fromStart(), path1.end());

	OpenPath::iterator i = joined.fromStart();

	Vector2 point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	OpenPath reversed;
	reversed.appendPoints(path2.fromEnd(), path2.rend());
	reversed.appendPoints(path1.fromEnd(), path1.rend());

	i = reversed.fromStart();

	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	OpenPath mixed;
	mixed.appendPoints(path1.fromStart(), path1.end());
	mixed.appendPoints(path2.fromEnd(), path2.rend());

	i = mixed.fromStart();

	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

}

void LoopPathTestCase::testOpenToLoopPathJoin() {
	OpenPath open;
	open.appendPoint(Vector2(1, 1));
	open.appendPoint(Vector2(2, 2));

	Loop loop(Vector2(3, 3));
	Loop::cw_iterator insert = loop.clockwise();
	insert = loop.insertPoint(Vector2(3, 4), insert);
	insert = loop.insertPoint(Vector2(4, 3), insert);

	LoopPath lp(loop, loop.clockwise(Vector2(3, 3)),
				loop.counterClockwise(Vector2(3, 3)));

	OpenPath joined;
	joined.appendPoints(open.fromStart(), open.end());
	joined.appendPoints(lp.fromStart(), lp.end());

	OpenPath::iterator i = joined.fromStart();

	Vector2 point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	CPPUNIT_ASSERT(i == joined.end());
}
<commit_msg>Repaired loop entry point iteration test<commit_after>#include "UnitTestUtils.h"
#include "LoopPathTestCase.h"

#include "mgl/loop_path.h"

#include <iostream>
#include <sstream>

using namespace std;
using namespace mgl;
using namespace libthing;

CPPUNIT_TEST_SUITE_REGISTRATION( LoopPathTestCase );

void LoopPathTestCase::setUp() {
	cout << endl << "No setup" << endl;
}

void LoopPathTestCase::testOpenPathBasic() {
	cout << "Testing basic OpenPath functionality" << endl;

	OpenPath path;

	path.appendPoint(Vector2(5, 5));
	OpenPath::iterator i = path.fromStart();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 5.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	++i;
	CPPUNIT_ASSERT(i == path.end());

	path.appendPoint(Vector2(5, 6));
	i = path.fromStart();
	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 5.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 6.0);

	++i;
	CPPUNIT_ASSERT(i == path.end());

	path.prependPoint(Vector2(6, 5));
	i = path.fromStart();
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	LineSegment2 seg = path.segmentAfterPoint(i);
	CPPUNIT_ASSERT_EQUAL(seg.length(), 1.0);

	OpenPath::entry_iterator entry = path.getEntryPoints();
	Vector2 first_entry = *entry;
	Vector2 start = *(path.fromStart());
	CPPUNIT_ASSERT_EQUAL(first_entry.x, start.x);
	CPPUNIT_ASSERT_EQUAL(first_entry.y, start.y);

	++entry;
	Vector2 second_entry = *entry;
	Vector2 end = *(path.fromEnd());
	CPPUNIT_ASSERT_EQUAL(second_entry.x, end.x);
	CPPUNIT_ASSERT_EQUAL(second_entry.y, end.y);

	Vector2 first_exit = path.getExitPoint(first_entry);
	CPPUNIT_ASSERT_EQUAL(first_exit.x, second_entry.x);
	CPPUNIT_ASSERT_EQUAL(first_exit.y, second_entry.y);

	Vector2 second_exit = path.getExitPoint(second_entry);
	CPPUNIT_ASSERT_EQUAL(second_exit.x, first_entry.x);
	CPPUNIT_ASSERT_EQUAL(second_exit.y, first_entry.y);
}

void LoopPathTestCase::testLoopBasic() {
	cout << "Testing single point loop" << endl;

	Loop loop(Vector2(2, 3));

	Loop::cw_iterator i = loop.clockwise();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 3.0);

	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 3.0);

	cout << "Testing two point loop" << endl;
	i = loop.insertPoint(Vector2(4, 5), i);
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	++i;
	second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 3.0);

	++i;
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 5.0);

	cout << "Testing three point loop" << endl;
	i = loop.insertPoint(Vector2(6, 7), i);
	Loop::ccw_iterator j = loop.counterClockwise(*i);
	first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 7.0);

	++i;
	second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 5.0);

	++i;
	Vector2 third = *i;
	CPPUNIT_ASSERT_EQUAL(third.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(third.y, 3.0);

	++i;
	Vector2 fourth = *i;
	CPPUNIT_ASSERT_EQUAL(fourth.x, 6.0);
	CPPUNIT_ASSERT_EQUAL(fourth.y, 7.0);

	cout << "Testing segmentAfterPoint" << endl;
	LineSegment2 seg = loop.segmentAfterPoint(i);
	CPPUNIT_ASSERT_EQUAL(seg.squaredLength(), 8.0);

	cout << "Testing entry points" << endl;
	int count = 0;
	Loop::entry_iterator entry = loop.entryBegin();
	for (;	entry != loop.entryEnd(); entry++){
		cout << "Entry " << count << "\t" << entry->x
				<< ", " << entry->y << endl;
		++count;
	}

	CPPUNIT_ASSERT_EQUAL(count, 3);

	Vector2 exitpoint = loop.getExitPoint(entry);
	Vector2 entrypoint = *entry;
	CPPUNIT_ASSERT_EQUAL(entrypoint.x, exitpoint.x);
	CPPUNIT_ASSERT_EQUAL(entrypoint.y, exitpoint.y);
}

void LoopPathTestCase::testLoopPathBasic() {
	Loop loop(Vector2(1, 2));

	Loop::cw_iterator last = loop.insertPoint(Vector2(3, 4), loop.clockwise());

	LoopPath lp(loop, loop.clockwise(Vector2(1, 2)),
			loop.counterClockwise(Vector2(1, 2)));

	LoopPath::iterator i = lp.fromStart();
	Vector2 first = *i;
	CPPUNIT_ASSERT_EQUAL(first.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(first.y, 2.0);

	++i;
	Vector2 second = *i;
	CPPUNIT_ASSERT_EQUAL(second.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(second.y, 4.0);

	++i;
	bool res = i == lp.end();
	CPPUNIT_ASSERT(res);
}

void LoopPathTestCase::testOpenPathJoin() {
	OpenPath path1;
	path1.appendPoint(Vector2(1, 1));
	path1.appendPoint(Vector2(2, 2));

	OpenPath path2;
	path2.appendPoint(Vector2(3, 3));
	path2.appendPoint(Vector2(4, 4));

	OpenPath joined;
	joined.appendPoints(path1.fromStart(), path1.end());

	OpenPath::iterator i = joined.fromStart();

	Vector2 point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	OpenPath reversed;
	reversed.appendPoints(path2.fromEnd(), path2.rend());
	reversed.appendPoints(path1.fromEnd(), path1.rend());

	i = reversed.fromStart();

	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	OpenPath mixed;
	mixed.appendPoints(path1.fromStart(), path1.end());
	mixed.appendPoints(path2.fromEnd(), path2.rend());

	i = mixed.fromStart();

	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

}

void LoopPathTestCase::testOpenToLoopPathJoin() {
	OpenPath open;
	open.appendPoint(Vector2(1, 1));
	open.appendPoint(Vector2(2, 2));

	Loop loop(Vector2(3, 3));
	Loop::cw_iterator insert = loop.clockwise();
	insert = loop.insertPoint(Vector2(3, 4), insert);
	insert = loop.insertPoint(Vector2(4, 3), insert);

	LoopPath lp(loop, loop.clockwise(Vector2(3, 3)),
				loop.counterClockwise(Vector2(3, 3)));

	OpenPath joined;
	joined.appendPoints(open.fromStart(), open.end());
	joined.appendPoints(lp.fromStart(), lp.end());

	OpenPath::iterator i = joined.fromStart();

	Vector2 point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 1.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 1.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 2.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 2.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 4.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 4.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	point = *i;
	CPPUNIT_ASSERT_EQUAL(point.x, 3.0);
	CPPUNIT_ASSERT_EQUAL(point.y, 3.0);

	++i;
	CPPUNIT_ASSERT(i == joined.end());
}
<|endoftext|>