<commit_before>//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This coordinates the per-module state used while generating code.
//
//===----------------------------------------------------------------------===//

#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;

CodeGenModule::CodeGenModule(ASTContext &C, llvm::Module &M)
  : Context(C), TheModule(M), Types(C.Target) {}

llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const Decl *D) {
  // See if it is already in the map.
  llvm::Constant *&Entry = GlobalDeclMap[D];
  if (Entry) return Entry;

  QualType ASTTy = cast<ValueDecl>(D)->getType();
  const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
  if (isa<FunctionDecl>(D)) {
    const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
    // FIXME: param attributes for sext/zext etc.
    return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
                                      D->getName(), &getModule());
  }

  assert(isa<FileVarDecl>(D) && "Unknown global decl!");

  return Entry = new llvm::GlobalVariable(Ty, false,
                                          llvm::GlobalValue::ExternalLinkage,
                                          0, D->getName(), &getModule());
}

void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
  // If this is not a prototype, emit the body.
  if (FD->getBody())
    CodeGenFunction(*this).GenerateCode(FD);
}

void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
  llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalDecl(D));

  // If the storage class is external and there is no initializer, just leave it
  // as a declaration.
  if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
    return;

  // Otherwise, convert the initializer, or use zero if appropriate.
  llvm::Constant *Init;
  if (D->getInit() == 0)
    Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
  else
    assert(D->getInit() == 0 && "FIXME: Global variable initializers unimp!");

  GV->setInitializer(Init);

  // Set the llvm linkage type as appropriate.
  // FIXME: This isn't right.  This should handle common linkage and other
  // stuff.
  switch (D->getStorageClass()) {
  case VarDecl::Auto:
  case VarDecl::Register:
    assert(0 && "Can't have auto or register globals");
  case VarDecl::None:
  case VarDecl::Extern:
    // todo: common
    break;
  case VarDecl::Static:
    GV->setLinkage(llvm::GlobalVariable::InternalLinkage);
    break;
  }
}

/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified
/// declarator chain.
void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) {
  for (; D; D = cast_or_null<FileVarDecl>(D->getNextDeclarator()))
    EmitGlobalVar(D);
}

llvm::Function *CodeGenModule::getMemCpyFn() {
  if (MemCpyFn) return MemCpyFn;
  llvm::Intrinsic::ID IID;
  switch (Context.Target.getPointerWidth(SourceLocation())) {
  default: assert(0 && "Unknown ptr width");
  case 32: IID = llvm::Intrinsic::memcpy_i32; break;
  case 64: IID = llvm::Intrinsic::memcpy_i64; break;
  }
  return MemCpyFn = llvm::Intrinsic::getDeclaration(&TheModule, IID);
}
<commit_msg>Implement trivial integer initializers, like 'int X = 4;' for global vars.  Approach suggested by Keith.<commit_after>//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This coordinates the per-module state used while generating code.
//
//===----------------------------------------------------------------------===//

#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;

CodeGenModule::CodeGenModule(ASTContext &C, llvm::Module &M)
  : Context(C), TheModule(M), Types(C.Target) {}

llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const Decl *D) {
  // See if it is already in the map.
  llvm::Constant *&Entry = GlobalDeclMap[D];
  if (Entry) return Entry;

  QualType ASTTy = cast<ValueDecl>(D)->getType();
  const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
  if (isa<FunctionDecl>(D)) {
    const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
    // FIXME: param attributes for sext/zext etc.
    return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
                                      D->getName(), &getModule());
  }

  assert(isa<FileVarDecl>(D) && "Unknown global decl!");

  return Entry = new llvm::GlobalVariable(Ty, false,
                                          llvm::GlobalValue::ExternalLinkage,
                                          0, D->getName(), &getModule());
}

void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
  // If this is not a prototype, emit the body.
  if (FD->getBody())
    CodeGenFunction(*this).GenerateCode(FD);
}

void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
  llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalDecl(D));

  // If the storage class is external and there is no initializer, just leave it
  // as a declaration.
  if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
    return;

  // Otherwise, convert the initializer, or use zero if appropriate.
  llvm::Constant *Init = 0;
  if (D->getInit() == 0) {
    Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
  } else if (D->getType()->isIntegerType()) {
    llvm::APSInt Value(getContext().getTypeSize(D->getInit()->getType()));
    if (D->getInit()->isIntegerConstantExpr(Value))
      Init = llvm::ConstantInt::get(Value);
  }
  assert(Init && "FIXME: Global variable initializers unimp!");

  GV->setInitializer(Init);

  // Set the llvm linkage type as appropriate.
  // FIXME: This isn't right.  This should handle common linkage and other
  // stuff.
  switch (D->getStorageClass()) {
  case VarDecl::Auto:
  case VarDecl::Register:
    assert(0 && "Can't have auto or register globals");
  case VarDecl::None:
  case VarDecl::Extern:
    // todo: common
    break;
  case VarDecl::Static:
    GV->setLinkage(llvm::GlobalVariable::InternalLinkage);
    break;
  }
}

/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified
/// declarator chain.
void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) {
  for (; D; D = cast_or_null<FileVarDecl>(D->getNextDeclarator()))
    EmitGlobalVar(D);
}

llvm::Function *CodeGenModule::getMemCpyFn() {
  if (MemCpyFn) return MemCpyFn;
  llvm::Intrinsic::ID IID;
  switch (Context.Target.getPointerWidth(SourceLocation())) {
  default: assert(0 && "Unknown ptr width");
  case 32: IID = llvm::Intrinsic::memcpy_i32; break;
  case 64: IID = llvm::Intrinsic::memcpy_i64; break;
  }
  return MemCpyFn = llvm::Intrinsic::getDeclaration(&TheModule, IID);
}
<|endoftext|>


<commit_before>#include <aleph/math/Bootstrap.hh>
#include <aleph/math/PiecewiseLinearFunction.hh>

#include <aleph/utilities/String.hh>

#include <fstream>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>

#include <getopt.h>

#include <cmath>

using DataType = double;
using Function = aleph::math::PiecewiseLinearFunction<DataType>;

Function load( const std::string& filename )
{
  std::ifstream in( filename );
  if( !in )
    throw std::runtime_error( "Unable to open file for reading" );

  std::string line;
  std::vector< std::pair<DataType, DataType> > data;

  while( std::getline( in, line ) )
  {
    line = aleph::utilities::trim( line );

    if( line.empty() || line.front() == '#' )
      continue;

    DataType x = DataType();
    DataType y = DataType();

    std::istringstream converter( line );

    converter >> x >> y;

    if( !converter )
      throw std::runtime_error( "Conversion failed" );

    data.push_back( std::make_pair(x,y) );
  }

  return Function( data.begin(), data.end() );
}

auto meanCalculation = [] ( auto begin, auto end )
{
  using T  = typename std::iterator_traits<decltype(begin)>::value_type;
  auto sum = std::accumulate( begin, end, T() );

  return sum / static_cast<double>( std::distance(begin, end) );
};

int main( int argc, char** argv )
{
  DataType alpha               = 0.05;
  unsigned numBootstrapSamples = 10;

  {
    static option commandLineOptions[] =
    {
      { "alpha", required_argument, nullptr, 'a' },
      { "n"    , required_argument, nullptr, 'n' },
      { nullptr, 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "a:", commandLineOptions, nullptr ) ) != - 1 )
    {
      switch( option )
      {
      case 'a':
        alpha = DataType( std::stod( optarg ) );
        break;
      case 'n':
        numBootstrapSamples = unsigned( std::stoull( optarg ) );
        break;
      default:
        break;
      }
    }
  }

  if( argc - optind <= 1 )
    return -1;

  // Load functions ----------------------------------------------------

  std::cerr << "* Loading functions...";

  std::vector<Function> functions;

  for( int i = optind; i < argc; i++ )
    functions.push_back( load( argv[i] ) );

  std::cerr << "finished\n";

  // Calculate mean ----------------------------------------------------

  std::cerr << "* Calculating empirical mean...";

  // This is the empirical mean that we obtain directly from the input
  // data. We do *not* make any assumptions about its distribution.
  auto empiricalMean = meanCalculation( functions.begin(), functions.end() );

  std::cerr << "finished\n";

  // These are the bootstrap replicates of the mean function. There's
  // one for every bootstrap sample.
  std::vector<Function> meanReplicates;
  meanReplicates.reserve( numBootstrapSamples );

  aleph::math::Bootstrap bootstrap;

  std::cerr << "* Calculating bootstrap replicates (n=" << numBootstrapSamples << ", m=" << functions.size() << ")...";

  bootstrap.makeReplicates( numBootstrapSamples,
                            functions.begin(), functions.end(),
                            meanCalculation,
                            std::back_inserter( meanReplicates ) );

  std::cerr << "finished\n";

  // This contains the population parameter of the corresponding
  // empirical process, viz. the *supremum* of the difference in
  // empirical mean and bootstrapped mean.
  std::vector<DataType> theta;
  theta.reserve( numBootstrapSamples );

  std::cerr << "* Calculating confidence band information...";

  for( auto&& meanReplicate : meanReplicates )
  {
    auto n = functions.size();
    auto f = std::sqrt( n ) * ( meanReplicate - empiricalMean );
    f      = f.abs();

    theta.push_back( f.sup() );
  }

  std::sort( theta.begin(), theta.end() );

  std::cerr << "finished\n";

  auto quantile = theta.at( bootstrap.index( numBootstrapSamples, alpha / 2 ) );
  auto fLower   = empiricalMean - quantile / std::sqrt( functions.size() );
  auto fUpper   = empiricalMean + quantile / std::sqrt( functions.size() );

  std::cout << empiricalMean << "\n\n"
            << fUpper        << "\n\n"
            << fLower        << "\n";
}
<commit_msg>Fixed quantile calculations<commit_after>#include <aleph/math/Bootstrap.hh>
#include <aleph/math/PiecewiseLinearFunction.hh>

#include <aleph/utilities/String.hh>

#include <fstream>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>

#include <getopt.h>

#include <cmath>

using DataType = double;
using Function = aleph::math::PiecewiseLinearFunction<DataType>;

Function load( const std::string& filename )
{
  std::ifstream in( filename );
  if( !in )
    throw std::runtime_error( "Unable to open file for reading" );

  std::string line;
  std::vector< std::pair<DataType, DataType> > data;

  while( std::getline( in, line ) )
  {
    line = aleph::utilities::trim( line );

    if( line.empty() || line.front() == '#' )
      continue;

    DataType x = DataType();
    DataType y = DataType();

    std::istringstream converter( line );

    converter >> x >> y;

    if( !converter )
      throw std::runtime_error( "Conversion failed" );

    data.push_back( std::make_pair(x,y) );
  }

  return Function( data.begin(), data.end() );
}

auto meanCalculation = [] ( auto begin, auto end )
{
  using T  = typename std::iterator_traits<decltype(begin)>::value_type;
  auto sum = std::accumulate( begin, end, T() );

  return sum / static_cast<double>( std::distance(begin, end) );
};

int main( int argc, char** argv )
{
  DataType alpha               = 0.05;
  unsigned numBootstrapSamples = 10;

  {
    static option commandLineOptions[] =
    {
      { "alpha", required_argument, nullptr, 'a' },
      { "n"    , required_argument, nullptr, 'n' },
      { nullptr, 0                , nullptr,  0  }
    };

    int option = 0;
    while( ( option = getopt_long( argc, argv, "a:", commandLineOptions, nullptr ) ) != - 1 )
    {
      switch( option )
      {
      case 'a':
        alpha = DataType( std::stod( optarg ) );
        break;
      case 'n':
        numBootstrapSamples = unsigned( std::stoull( optarg ) );
        break;
      default:
        break;
      }
    }
  }

  if( argc - optind <= 1 )
    return -1;

  // Load functions ----------------------------------------------------

  std::cerr << "* Loading functions...";

  std::vector<Function> functions;

  for( int i = optind; i < argc; i++ )
    functions.push_back( load( argv[i] ) );

  std::cerr << "finished\n";

  // Calculate mean ----------------------------------------------------

  std::cerr << "* Calculating empirical mean...";

  // This is the empirical mean that we obtain directly from the input
  // data. We do *not* make any assumptions about its distribution.
  auto empiricalMean = meanCalculation( functions.begin(), functions.end() );

  std::cerr << "finished\n";

  // These are the bootstrap replicates of the mean function. There's
  // one for every bootstrap sample.
  std::vector<Function> meanReplicates;
  meanReplicates.reserve( numBootstrapSamples );

  aleph::math::Bootstrap bootstrap;

  std::cerr << "* Calculating bootstrap replicates (n=" << numBootstrapSamples << ", m=" << functions.size() << ")...";

  bootstrap.makeReplicates( numBootstrapSamples,
                            functions.begin(), functions.end(),
                            meanCalculation,
                            std::back_inserter( meanReplicates ) );

  std::cerr << "finished\n";

  // This contains the population parameter of the corresponding
  // empirical process, viz. the *supremum* of the difference in
  // empirical mean and bootstrapped mean.
  std::vector<DataType> theta;
  theta.reserve( numBootstrapSamples );

  std::cerr << "* Calculating confidence band information...";

  for( auto&& meanReplicate : meanReplicates )
  {
    auto n = functions.size();
    auto f = std::sqrt( n ) * ( meanReplicate - empiricalMean );
    f      = f.abs();

    theta.push_back( f.sup() );
  }

  std::sort( theta.begin(), theta.end() );

  std::cerr << "finished\n";

  auto quantile = theta.at( bootstrap.index( numBootstrapSamples, 1.0 - alpha ) );
  auto fLower   = empiricalMean - quantile / std::sqrt( functions.size() );
  auto fUpper   = empiricalMean + quantile / std::sqrt( functions.size() );

  std::cout << empiricalMean << "\n\n"
            << fUpper        << "\n\n"
            << fLower        << "\n";
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016-2017 The Brenwill Workshop Ltd.
 *
 * 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.
 */

#ifndef SPIRV_CROSS_MSL_HPP
#define SPIRV_CROSS_MSL_HPP

#include "spirv_glsl.hpp"
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace spirv_cross
{

// Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr
{
	uint32_t location = 0;
	uint32_t msl_buffer = 0;
	uint32_t msl_offset = 0;
	uint32_t msl_stride = 0;
	bool per_instance = false;
	bool used_by_shader = false;
};

// Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture,
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding
{
	spv::ExecutionModel stage;
	uint32_t desc_set = 0;
	uint32_t binding = 0;

	uint32_t msl_buffer = 0;
	uint32_t msl_texture = 0;
	uint32_t msl_sampler = 0;

	bool used_by_shader = false;
};

// Tracks the type ID and member index of a struct member
using MSLStructMemberKey = uint64_t;

// Special constant used in a MSLResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstDescSet = UINT32_MAX;

// Special constant used in a MSLResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;

// Decompiles SPIR-V to Metal Shading Language
class CompilerMSL : public CompilerGLSL
{
public:
	// Options for compiling to Metal Shading Language
	struct Options
	{
		bool flip_vert_y = false;
		bool flip_frag_y = false;
		bool is_rendering_points = false;
		bool pad_and_pack_uniform_structs = false;
		std::string entry_point_name;
	};

	const Options &get_options() const
	{
		return options;
	}

	void set_options(Options &opts)
	{
		options = opts;
	}

	// Constructs an instance to compile the SPIR-V code into Metal Shading Language,
	// using the configuration parameters, if provided:
	//  - p_vtx_attrs is an optional list of vertex attribute bindings used to match
	//    vertex content locations to MSL attributes. If vertex attributes are provided,
	//    the compiler will set the used_by_shader flag to true in any vertex attribute
	//    actually used by the MSL code.
	//  - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
	//    texture or sampler index to use for a particular SPIR-V description set
	//    and binding. If resource bindings are provided, the compiler will set the
	//    used_by_shader flag to true in any resource binding actually used by the MSL code.
	CompilerMSL(std::vector<uint32_t> spirv, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
	            std::vector<MSLResourceBinding> *p_res_bindings = nullptr);

	// Compiles the SPIR-V code into Metal Shading Language.
	std::string compile() override;

	// Compiles the SPIR-V code into Metal Shading Language, overriding configuration parameters.
	// Any of the parameters here may be null to indicate that the configuration provided in the
	// constructor should be used. They are not declared as optional to avoid a conflict with the
	// inherited and overridden zero-parameter compile() function.
	std::string compile(std::vector<MSLVertexAttr> *p_vtx_attrs, std::vector<MSLResourceBinding> *p_res_bindings);

	// This legacy method is deprecated.
	typedef Options MSLConfiguration;
	std::string compile(MSLConfiguration &msl_cfg, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
	                    std::vector<MSLResourceBinding> *p_res_bindings = nullptr);

protected:
	void emit_instruction(const Instruction &instr) override;
	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
	                  uint32_t count) override;
	void emit_header() override;
	void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
	void emit_fixup() override;
	void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
	                        const std::string &qualifier = "") override;
	std::string type_to_glsl(const SPIRType &type) override;
	std::string image_type_glsl(const SPIRType &type) override;
	std::string builtin_to_glsl(spv::BuiltIn builtin) override;
	std::string constant_expression(const SPIRConstant &c) override;
	size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
	std::string to_func_call_arg(uint32_t id) override;
	std::string to_name(uint32_t id, bool allow_alias = true) const override;
	std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
	                             bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
	                             bool has_dref) override;
	std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
	                             uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x,
	                             uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
	                             uint32_t comp, uint32_t sample, bool *p_forward) override;
	std::string unpack_expression_type(std::string expr_str, const SPIRType &type) override;

	std::string get_argument_address_space(const SPIRVariable &argument);

	void preprocess_op_codes();
	void emit_custom_functions();
	void localize_global_variables();
	void extract_global_variables_from_functions();

	std::unordered_map<uint32_t, std::set<uint32_t>> function_global_vars;
	void extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
	                                            std::unordered_set<uint32_t> &global_var_ids,
	                                            std::unordered_set<uint32_t> &processed_func_ids);
	uint32_t add_interface_block(spv::StorageClass storage);
	void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);

	void emit_resources();
	void emit_interface_block(uint32_t ib_var_id);
	void populate_func_name_overrides();
	void populate_var_name_overrides();

	std::string func_type_decl(SPIRType &type);
	std::string clean_func_name(std::string func_name) override;
	std::string entry_point_args(bool append_comma);
	std::string get_entry_point_name();
	std::string to_qualified_member_name(const SPIRType &type, uint32_t index);
	std::string ensure_valid_name(std::string name, std::string pfx);
	std::string to_sampler_expression(uint32_t id);
	std::string builtin_qualifier(spv::BuiltIn builtin);
	std::string builtin_type_decl(spv::BuiltIn builtin);
	std::string built_in_func_arg(spv::BuiltIn builtin, bool prefix_comma);
	std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
	std::string argument_decl(const SPIRFunction::Parameter &arg);
	uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype);
	uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
	size_t get_declared_type_size(uint32_t type_id) const;
	size_t get_declared_type_size(uint32_t type_id, uint64_t dec_mask) const;
	size_t get_declared_struct_member_alignment(const SPIRType &struct_type, uint32_t index) const;
	size_t get_declared_type_alignment(uint32_t type_id, uint64_t dec_mask) const;
	std::string to_component_argument(uint32_t id);
	void exclude_from_stage_in(SPIRVariable &var);
	void exclude_member_from_stage_in(const SPIRType &type, uint32_t index);
	std::string add_input_buffer_block_member(uint32_t mbr_type_id, std::string mbr_name, uint32_t mbr_locn);
	uint32_t get_input_buffer_block_var_id(uint32_t msl_buffer);
	void align_struct(SPIRType &ib_type);
	bool is_member_packable(SPIRType &ib_type, uint32_t index);
	MSLStructMemberKey get_struct_member_key(uint32_t type_id, uint32_t index);

	Options options;
	std::unordered_map<std::string, std::string> func_name_overrides;
	std::unordered_map<std::string, std::string> var_name_overrides;
	std::set<uint32_t> custom_function_ops;
	std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;
	std::map<uint32_t, uint32_t> non_stage_in_input_var_ids;
	std::unordered_map<MSLStructMemberKey, uint32_t> struct_member_padding;
	std::vector<MSLResourceBinding *> resource_bindings;
	MSLResourceBinding next_metal_resource_index;
	uint32_t stage_in_var_id = 0;
	uint32_t stage_out_var_id = 0;
	uint32_t stage_uniforms_var_id = 0;
	bool needs_vertex_idx_arg = false;
	bool needs_instance_idx_arg = false;
	std::string qual_pos_var_name;
	std::string stage_in_var_name = "in";
	std::string stage_out_var_name = "out";
	std::string stage_uniform_var_name = "uniforms";
	std::string sampler_name_suffix = "Smplr";

	// OpcodeHandler that handles several MSL preprocessing operations.
	struct OpCodePreprocessor : OpcodeHandler
	{
		OpCodePreprocessor(CompilerMSL &compiler_)
		    : compiler(compiler_)
		{
		}

		bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;

		CompilerMSL &compiler;
		bool suppress_missing_prototypes = false;
	};

	// Sorts the members of a SPIRType and associated Meta info based on a settable sorting
	// aspect, which defines which aspect of the struct members will be used to sort them.
	// Regardless of the sorting aspect, built-in members always appear at the end of the struct.
	struct MemberSorter
	{
		enum SortAspect
		{
			Location,
			LocationReverse,
			Offset,
			OffsetThenLocationReverse,
			Alphabetical
		};

		void sort();
		bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
		MemberSorter(SPIRType &t, Meta &m, SortAspect sa);

		SPIRType &type;
		Meta &meta;
		SortAspect sort_aspect;
	};
};
}

#endif
<commit_msg>CompilerMSL mark the legacy version of the compile() function as  deprecated.<commit_after>/*
 * Copyright 2016-2017 The Brenwill Workshop Ltd.
 *
 * 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.
 */

#ifndef SPIRV_CROSS_MSL_HPP
#define SPIRV_CROSS_MSL_HPP

#include "spirv_glsl.hpp"
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace spirv_cross
{

// Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr
{
	uint32_t location = 0;
	uint32_t msl_buffer = 0;
	uint32_t msl_offset = 0;
	uint32_t msl_stride = 0;
	bool per_instance = false;
	bool used_by_shader = false;
};

// Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture,
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding
{
	spv::ExecutionModel stage;
	uint32_t desc_set = 0;
	uint32_t binding = 0;

	uint32_t msl_buffer = 0;
	uint32_t msl_texture = 0;
	uint32_t msl_sampler = 0;

	bool used_by_shader = false;
};

// Tracks the type ID and member index of a struct member
using MSLStructMemberKey = uint64_t;

// Special constant used in a MSLResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstDescSet = UINT32_MAX;

// Special constant used in a MSLResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;

// Decompiles SPIR-V to Metal Shading Language
class CompilerMSL : public CompilerGLSL
{
public:
	// Options for compiling to Metal Shading Language
	struct Options
	{
		bool flip_vert_y = false;
		bool flip_frag_y = false;
		bool is_rendering_points = false;
		bool pad_and_pack_uniform_structs = false;
		std::string entry_point_name;
	};

	const Options &get_options() const
	{
		return options;
	}

	void set_options(Options &opts)
	{
		options = opts;
	}

	// Constructs an instance to compile the SPIR-V code into Metal Shading Language,
	// using the configuration parameters, if provided:
	//  - p_vtx_attrs is an optional list of vertex attribute bindings used to match
	//    vertex content locations to MSL attributes. If vertex attributes are provided,
	//    the compiler will set the used_by_shader flag to true in any vertex attribute
	//    actually used by the MSL code.
	//  - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
	//    texture or sampler index to use for a particular SPIR-V description set
	//    and binding. If resource bindings are provided, the compiler will set the
	//    used_by_shader flag to true in any resource binding actually used by the MSL code.
	CompilerMSL(std::vector<uint32_t> spirv, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
	            std::vector<MSLResourceBinding> *p_res_bindings = nullptr);

	// Compiles the SPIR-V code into Metal Shading Language.
	std::string compile() override;

	// Compiles the SPIR-V code into Metal Shading Language, overriding configuration parameters.
	// Any of the parameters here may be null to indicate that the configuration provided in the
	// constructor should be used. They are not declared as optional to avoid a conflict with the
	// inherited and overridden zero-parameter compile() function.
	std::string compile(std::vector<MSLVertexAttr> *p_vtx_attrs, std::vector<MSLResourceBinding> *p_res_bindings);

	// This legacy method is deprecated.
	typedef Options MSLConfiguration;
	SPIRV_CROSS_DEPRECATED("Please use get_options() and set_options() instead.")
	std::string compile(MSLConfiguration &msl_cfg, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
	                    std::vector<MSLResourceBinding> *p_res_bindings = nullptr);

protected:
	void emit_instruction(const Instruction &instr) override;
	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
	                  uint32_t count) override;
	void emit_header() override;
	void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
	void emit_fixup() override;
	void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
	                        const std::string &qualifier = "") override;
	std::string type_to_glsl(const SPIRType &type) override;
	std::string image_type_glsl(const SPIRType &type) override;
	std::string builtin_to_glsl(spv::BuiltIn builtin) override;
	std::string constant_expression(const SPIRConstant &c) override;
	size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
	std::string to_func_call_arg(uint32_t id) override;
	std::string to_name(uint32_t id, bool allow_alias = true) const override;
	std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
	                             bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
	                             bool has_dref) override;
	std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
	                             uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x,
	                             uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
	                             uint32_t comp, uint32_t sample, bool *p_forward) override;
	std::string unpack_expression_type(std::string expr_str, const SPIRType &type) override;

	std::string get_argument_address_space(const SPIRVariable &argument);

	void preprocess_op_codes();
	void emit_custom_functions();
	void localize_global_variables();
	void extract_global_variables_from_functions();

	std::unordered_map<uint32_t, std::set<uint32_t>> function_global_vars;
	void extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
	                                            std::unordered_set<uint32_t> &global_var_ids,
	                                            std::unordered_set<uint32_t> &processed_func_ids);
	uint32_t add_interface_block(spv::StorageClass storage);
	void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);

	void emit_resources();
	void emit_interface_block(uint32_t ib_var_id);
	void populate_func_name_overrides();
	void populate_var_name_overrides();

	std::string func_type_decl(SPIRType &type);
	std::string clean_func_name(std::string func_name) override;
	std::string entry_point_args(bool append_comma);
	std::string get_entry_point_name();
	std::string to_qualified_member_name(const SPIRType &type, uint32_t index);
	std::string ensure_valid_name(std::string name, std::string pfx);
	std::string to_sampler_expression(uint32_t id);
	std::string builtin_qualifier(spv::BuiltIn builtin);
	std::string builtin_type_decl(spv::BuiltIn builtin);
	std::string built_in_func_arg(spv::BuiltIn builtin, bool prefix_comma);
	std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
	std::string argument_decl(const SPIRFunction::Parameter &arg);
	uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype);
	uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
	size_t get_declared_type_size(uint32_t type_id) const;
	size_t get_declared_type_size(uint32_t type_id, uint64_t dec_mask) const;
	size_t get_declared_struct_member_alignment(const SPIRType &struct_type, uint32_t index) const;
	size_t get_declared_type_alignment(uint32_t type_id, uint64_t dec_mask) const;
	std::string to_component_argument(uint32_t id);
	void exclude_from_stage_in(SPIRVariable &var);
	void exclude_member_from_stage_in(const SPIRType &type, uint32_t index);
	std::string add_input_buffer_block_member(uint32_t mbr_type_id, std::string mbr_name, uint32_t mbr_locn);
	uint32_t get_input_buffer_block_var_id(uint32_t msl_buffer);
	void align_struct(SPIRType &ib_type);
	bool is_member_packable(SPIRType &ib_type, uint32_t index);
	MSLStructMemberKey get_struct_member_key(uint32_t type_id, uint32_t index);

	Options options;
	std::unordered_map<std::string, std::string> func_name_overrides;
	std::unordered_map<std::string, std::string> var_name_overrides;
	std::set<uint32_t> custom_function_ops;
	std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;
	std::map<uint32_t, uint32_t> non_stage_in_input_var_ids;
	std::unordered_map<MSLStructMemberKey, uint32_t> struct_member_padding;
	std::vector<MSLResourceBinding *> resource_bindings;
	MSLResourceBinding next_metal_resource_index;
	uint32_t stage_in_var_id = 0;
	uint32_t stage_out_var_id = 0;
	uint32_t stage_uniforms_var_id = 0;
	bool needs_vertex_idx_arg = false;
	bool needs_instance_idx_arg = false;
	std::string qual_pos_var_name;
	std::string stage_in_var_name = "in";
	std::string stage_out_var_name = "out";
	std::string stage_uniform_var_name = "uniforms";
	std::string sampler_name_suffix = "Smplr";

	// OpcodeHandler that handles several MSL preprocessing operations.
	struct OpCodePreprocessor : OpcodeHandler
	{
		OpCodePreprocessor(CompilerMSL &compiler_)
		    : compiler(compiler_)
		{
		}

		bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;

		CompilerMSL &compiler;
		bool suppress_missing_prototypes = false;
	};

	// Sorts the members of a SPIRType and associated Meta info based on a settable sorting
	// aspect, which defines which aspect of the struct members will be used to sort them.
	// Regardless of the sorting aspect, built-in members always appear at the end of the struct.
	struct MemberSorter
	{
		enum SortAspect
		{
			Location,
			LocationReverse,
			Offset,
			OffsetThenLocationReverse,
			Alphabetical
		};

		void sort();
		bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
		MemberSorter(SPIRType &t, Meta &m, SortAspect sa);

		SPIRType &type;
		Meta &meta;
		SortAspect sort_aspect;
	};
};
}

#endif
<|endoftext|>


<commit_before>#include "washingCycleTask.h"

washingCycleTask::washingCycleTask(machineInteractionTask * machine):
	RTOS::task(15,"washing cycle"),
	ongoing(),
	currentStep(),
	state(cycleState::STOP),
	machine(machine),
	CycleFlag((RTOS::task*)this,"WCT_newCycleFlag"),
	runFlag((RTOS::task*)this, "WCT_runFlag"),
	updateFlag((RTOS::task*)this,"WCT_updateFlag"),
	pauseFlag((RTOS::task*)this, "WCT_pauseFlag"),
	stopFlag((RTOS::task*)this, "WCT_stopFlag"),
	machineStatePool("WCT_machineStatePool"),
	newCyclePool("WCT_newCyclePool"),
	currentStepTimer((RTOS::task*)this,"WCT_currentStepTmr"),
	listeners(),
	washingCycles()
{
    cycleID defaultID("cycle1", "Admin");
	washingCycle cycle(defaultID);
	cycleStep step1 = {"step1",40,60,false,0}; cycle.addStep(step1);
	cycleStep step2 = {"step2",40,60,false,0}; cycle.addStep(step2);
	cycleStep step3 = {"step3",40,60,true,0}; cycle.addStep(step3);
	cycleStep step4 = {"step4",40,60,false,1600, 30, false}; cycle.addStep(step4);
	cycleStep step5 = {"step5",20,0,false,0, 60, true}; cycle.addStep(step5);
	addWashingCycle(cycle);
	loadCycle(defaultID);
	this->run();
}

void washingCycleTask::stateChanged(const MachineState& currentState){
	internalMachineState toWrite;
	toWrite.temperature = currentState.temperature;
	toWrite.waterLevel = currentState.waterLevel;
	this->machineStatePool.write(toWrite);
	this->updateFlag.set();

}

void washingCycleTask::addCycleStateListener(cycleStateListener* listener){
	this->listeners.push_back(listener);
}

void washingCycleTask::loadCycle(const cycleID& toLoad)
{
#ifdef DEBUG
	std::cout << "loadCycle called..." << std::endl;
#endif
	washingCycle cycle = findUserWashingCycle(toLoad);
	if(cycle == toLoad)
	{
#ifdef DEBUG
		std::cout << "loading cycle " << toLoad.name << std::endl;
#endif
		this->CycleFlag.set();
		this->newCyclePool.write(cycle);
	}
}

void washingCycleTask::addWashingCycle(washingCycle& cycle)
{
	washingCycles.push_back(cycle);
}

std::vector<std::string> washingCycleTask::getWashingCycleNames(std::string userName)
{
	std::vector<std::string> cycleNames;
	std::vector<washingCycle>::iterator cycle = this->washingCycles.begin();
	for(;cycle != this->washingCycles.end(); ++cycle)
	{
		if(cycle->getUser() == userName)
		{
			cycleNames.push_back(cycle->getName());
		}
	}
	return cycleNames;
}

int washingCycleTask::getTotalCycleSteps(const cycleID& toFind)const
{
	washingCycle temp = this->findUserWashingCycle(toFind);
	if(temp == toFind)
	{
		return temp.totalSteps();
	}
	return -1;
}

washingCycle washingCycleTask::findUserWashingCycle(const cycleID& toFind)const
{
	std::vector<washingCycle>::const_iterator cycle =
		this->washingCycles.begin();
	for(;cycle != this->washingCycles.end(); ++cycle)
	{
		if((*cycle) == toFind)
		{
			return *cycle;
		}
	}
	washingCycle defaultVal;
	return defaultVal;
}

void washingCycleTask::pause(){
	this->pauseFlag.set();
}

void washingCycleTask::run(){
	this->runFlag.set();
}

void washingCycleTask::stop(){
	this->stopFlag.set();
}

bool washingCycleTask::assessProgress(){
	//timed steps are handled by the timer, and don't need further confirmation.
	if (currentStep.isTimed()){
		return false;
	}
	//non-timed tasks finish when the water level and temperature are equal to,
	//or greater than the expected level. Assume the MIT is responsible for
	//keeping the balance.
	if(this->knownState.temperature < this->currentStep.getTemperature() ||
		this->knownState.waterLevel < this->currentStep.getWaterLevel()){
		return false;
	}
	return true;
}

void washingCycleTask::notifyListeners(){
	std::vector<cycleStateListener*>::iterator listen = this->listeners.begin();

	switch(this->state){
		case cycleState::STOP:{
			bool properEnd = this->currentStep.isFinal();
			for(;listen != this->listeners.end(); ++listen){
				(*listen)->cycleEnded(properEnd,
					this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
		case cycleState::PAUSE:{
			for (;listen != this->listeners.end(); ++listen){
				(*listen)->cyclePaused(this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
		case cycleState::RUN:{
			for (;listen != this->listeners.end(); ++listen){
				(*listen)->cycleStateChanged(this->ongoing.totalSteps(),
					this->ongoing.currentStepNumber(),
					this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
	}
}

void washingCycleTask::toStandBy(){
	this->machine->setTemperature(20);
	this->machine->setWaterLevel(0);
	this->machine->setRPM(false,0);
	this->machine->setDetergent(false);
}

void washingCycleTask::updateMachine(){
	if(this->state != cycleState::RUN)
	{
		if (this->machine->isRunning())
		{
			this->machine->setMachineState(false);
		}
		return;
	}
	else
	{
		if (! this->machine->isRunning())
		{
			this->machine->setMachineState(true);
		}
	}

	if(currentStep.isTimed()){
		trace;
		this->currentStepTimer.set(
			(this->currentStep.getDuration()) S);
	}

	if (this->currentStep.mustFlush()){
		this->machine->flush();
	}else{
		this->machine->setTemperature(
			this->currentStep.getTemperature());

		this->machine->setWaterLevel(
			this->currentStep.getWaterLevel());
	}

	this->machine->setRPM(
		this->currentStep.isDrumClockwise(),
		this->currentStep.getDrumSpeed());

	this->machine->setDetergent(
		this->currentStep.getAddDetergent());
}

void washingCycleTask::main(){

	while (true)
	{
		//State: Stopped. Wait until instructed to run.
		this->wait(runFlag);
		state = cycleState::RUN;

		this->wait(CycleFlag);

		this->machine->setMachineState(true);
		ongoing = newCyclePool.read();
		currentStep = ongoing.getCurrent();

		while(this->ongoing.hasNext())
		{
			updateMachine();
			RTOS::event progress = this->wait(runFlag + pauseFlag + stopFlag +
											  updateFlag + currentStepTimer);
			bool brake = false;
#ifdef DEBUG
			std::cout << "hey."<<std::endl;
#endif

			if(progress == runFlag){
				state = cycleState::RUN;
			}else if(progress == stopFlag) {
				state = cycleState::STOP; brake = true;
			}else if(progress == pauseFlag){
				state = cycleState::PAUSE;
				toStandBy();
				currentStepTimer.cancel();
				notifyListeners();
				RTOS::event ev = this->wait(runFlag + stopFlag);
				if(ev == runFlag) {
					updateMachine(); notifyListeners();
				}else if(ev == stopFlag) {
					brake = true;
				}
			}else if(progress == currentStepTimer || assessProgress()){
				currentStep = ongoing.next(); updateMachine(); notifyListeners();
			}
			else if(progress == updateFlag){knownState = machineStatePool.read();}

			if (brake)
			{
				notifyListeners();
				break;
			}
		}
	}
}
<commit_msg>pair programming at its finest!<commit_after>#include "washingCycleTask.h"

washingCycleTask::washingCycleTask(machineInteractionTask * machine):
	RTOS::task(15,"washing cycle"),
	ongoing(),
	currentStep(),
	state(cycleState::STOP),
	machine(machine),
	CycleFlag((RTOS::task*)this,"WCT_newCycleFlag"),
	runFlag((RTOS::task*)this, "WCT_runFlag"),
	updateFlag((RTOS::task*)this,"WCT_updateFlag"),
	pauseFlag((RTOS::task*)this, "WCT_pauseFlag"),
	stopFlag((RTOS::task*)this, "WCT_stopFlag"),
	machineStatePool("WCT_machineStatePool"),
	newCyclePool("WCT_newCyclePool"),
	currentStepTimer((RTOS::task*)this,"WCT_currentStepTmr"),
	listeners(),
	washingCycles()
{
    cycleID defaultID("cycle1", "Admin");
	washingCycle cycle(defaultID);
	cycleStep step1 = {"step1",40,60,false,0}; cycle.addStep(step1);
	cycleStep step2 = {"step2",40,60,false,0}; cycle.addStep(step2);
	cycleStep step3 = {"step3",40,60,true,0}; cycle.addStep(step3);
	cycleStep step4 = {"step4",40,60,false,1600, 30, false}; cycle.addStep(step4);
	cycleStep step5 = {"step5",20,0,false,0, 60, true}; cycle.addStep(step5);
	addWashingCycle(cycle);
	loadCycle(defaultID);
	this->run();
}

void washingCycleTask::stateChanged(const MachineState& currentState){
	internalMachineState toWrite;
	toWrite.temperature = currentState.temperature;
	toWrite.waterLevel = currentState.waterLevel;
	this->machineStatePool.write(toWrite);
	this->updateFlag.set();

}

void washingCycleTask::addCycleStateListener(cycleStateListener* listener){
	this->listeners.push_back(listener);
}

void washingCycleTask::loadCycle(const cycleID& toLoad)
{
#ifdef DEBUG
	std::cout << "loadCycle called..." << std::endl;
#endif
	washingCycle cycle = findUserWashingCycle(toLoad);
	if(cycle == toLoad)
	{
#ifdef DEBUG
		std::cout << "loading cycle " << toLoad.name << std::endl;
#endif
		this->CycleFlag.set();
		this->newCyclePool.write(cycle);
	}
}

void washingCycleTask::addWashingCycle(washingCycle& cycle)
{
	washingCycles.push_back(cycle);
}

std::vector<std::string> washingCycleTask::getWashingCycleNames(std::string userName)
{
	std::vector<std::string> cycleNames;
	std::vector<washingCycle>::iterator cycle = this->washingCycles.begin();
	for(;cycle != this->washingCycles.end(); ++cycle)
	{
		if(cycle->getUser() == userName)
		{
			cycleNames.push_back(cycle->getName());
		}
	}
	return cycleNames;
}

int washingCycleTask::getTotalCycleSteps(const cycleID& toFind)const
{
	washingCycle temp = this->findUserWashingCycle(toFind);
	if(temp == toFind)
	{
		return temp.totalSteps();
	}
	return -1;
}

washingCycle washingCycleTask::findUserWashingCycle(const cycleID& toFind)const
{
	std::vector<washingCycle>::const_iterator cycle =
		this->washingCycles.begin();
	for(;cycle != this->washingCycles.end(); ++cycle)
	{
		if((*cycle) == toFind)
		{
			return *cycle;
		}
	}
	washingCycle defaultVal;
	return defaultVal;
}

void washingCycleTask::pause(){
	this->pauseFlag.set();
}

void washingCycleTask::run(){
	this->runFlag.set();
}

void washingCycleTask::stop(){
	this->stopFlag.set();
}

bool washingCycleTask::assessProgress(){
	//timed steps are handled by the timer, and don't need further confirmation.
	if (currentStep.isTimed()){
		return false;
	}
	//non-timed tasks finish when the water level and temperature are equal to,
	//or greater than the expected level. Assume the MIT is responsible for
	//keeping the balance.
	if(this->knownState.temperature < this->currentStep.getTemperature() ||
		this->knownState.waterLevel < this->currentStep.getWaterLevel()){
		return false;
	}
	return true;
}

void washingCycleTask::notifyListeners(){
	std::vector<cycleStateListener*>::iterator listen = this->listeners.begin();

	switch(this->state){
		case cycleState::STOP:{
			bool properEnd = this->currentStep.isFinal();
			for(;listen != this->listeners.end(); ++listen){
				(*listen)->cycleEnded(properEnd,
					this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
		case cycleState::PAUSE:{
			for (;listen != this->listeners.end(); ++listen){
				(*listen)->cyclePaused(this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
		case cycleState::RUN:{
			for (;listen != this->listeners.end(); ++listen){
				(*listen)->cycleStateChanged(this->ongoing.totalSteps(),
					this->ongoing.currentStepNumber(),
					this->ongoing.getName(),
					this->currentStep.getName());
			}
			break;
		}
	}
}

void washingCycleTask::toStandBy(){
	this->machine->setTemperature(20);
	this->machine->setWaterLevel(0);
	this->machine->setRPM(false,0);
	this->machine->setDetergent(false);
}

void washingCycleTask::updateMachine(){
	if(this->state != cycleState::RUN)
	{
		if (this->machine->isRunning())
		{
			this->machine->setMachineState(false);
		}
		return;
	}
	else
	{
		if (! this->machine->isRunning())
		{
			this->machine->setMachineState(true);
		}
	}

	if(currentStep.isTimed()){
		trace;
		this->currentStepTimer.set(
			(this->currentStep.getDuration()) S);
	}

	if (this->currentStep.mustFlush()){
		this->machine->flush();
	}else{
		this->machine->setTemperature(
			this->currentStep.getTemperature());

		this->machine->setWaterLevel(
			this->currentStep.getWaterLevel());
	}

	this->machine->setRPM(
		this->currentStep.isDrumClockwise(),
		this->currentStep.getDrumSpeed());

	this->machine->setDetergent(
		this->currentStep.getAddDetergent());
}

void washingCycleTask::main(){

	while (true)
	{
		//State: Stopped. Wait until instructed to run.
		this->wait(runFlag);
		state = cycleState::RUN;

		this->wait(CycleFlag);

		this->machine->setMachineState(true);
		ongoing = newCyclePool.read();
		currentStep = ongoing.getCurrent();

		while(this->ongoing.hasNext())
		{
			if (!this->current.isTimed())
			{
				updateMachine();
			}
			RTOS::event progress = this->wait(runFlag + pauseFlag + stopFlag +
											  updateFlag + currentStepTimer);
			bool brake = false;
#ifdef DEBUG
			std::cout << "hey."<<std::endl;
#endif

			if(progress == runFlag){
				state = cycleState::RUN;
			}else if(progress == stopFlag) {
				state = cycleState::STOP; brake = true;
			}else if(progress == pauseFlag){
				state = cycleState::PAUSE;
				toStandBy();
				currentStepTimer.cancel();
				notifyListeners();
				RTOS::event ev = this->wait(runFlag + stopFlag);
				if(ev == runFlag) {
					updateMachine(); notifyListeners();
				}else if(ev == stopFlag) {
					brake = true;
				}
			}else if(progress == currentStepTimer || assessProgress()){
				currentStep = ongoing.next(); updateMachine(); notifyListeners();
			}
			else if(progress == updateFlag){knownState = machineStatePool.read();}

			if (brake)
			{
				notifyListeners();
				break;
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "EventReceiverTest.h"
#include "Autowiring/Autowired.h"
#include "Autowiring/CoreThread.h"
#include <boost/thread/barrier.hpp>
#include <stdexcept>
#include <vector>

using namespace std;

class invalid_copycounter_exception:
  public runtime_error
{
public:
  invalid_copycounter_exception(void):
    runtime_error("Copy counter was moved, and incorrectly reused")
  {}
};

class CopyCounter {
public:
  CopyCounter(void):
    m_count(0)
  {}

  CopyCounter(const CopyCounter& rhs):
    m_count(rhs.m_count + 1)
  {
    rhs.Check();
  }

  /// <summary>
  /// Special case move ctor, which won't increment the count
  /// </summary>
  CopyCounter(CopyCounter&& rhs):
    m_count(rhs.m_count)
  {
    rhs.Check();
    rhs.m_count = -1;
  }

  /// <summary>
  /// Destructor, which invalidates the count in a specific way to indicate use-after-free
  /// </summary>
  ~CopyCounter(void) {
    m_count = -2;
  }

  // The actual count:
  int m_count;

  // Throws an exception if this copycounter is invalid
  void Check(void) const {
    if(m_count < 0)
      throw invalid_copycounter_exception();
  }

  // Copy and move overrides
  CopyCounter& operator=(const CopyCounter& rhs) {
    rhs.Check();
    m_count = rhs.m_count + 1;
    return *this;
  }

  CopyCounter& operator=(CopyCounter&& rhs) {
    rhs.Check();
    m_count = rhs.m_count;
    rhs.m_count = -1;
    return *this;
  }
};

class NoCopyClass
{
public:
  NoCopyClass():
    m_value(100)
  {}

  explicit NoCopyClass(NoCopyClass& rhs):
    m_value(101)
  {}

  int m_value;
};

class CallableInterface:
  public EventReceiver
{
public:
  virtual void ZeroArgs(void) = 0;
  virtual void OneArg(int arg) = 0;
  virtual void CopyVector(const vector<int>& vec) = 0;
  virtual void CopyVectorForwarded(vector<int>&& vec) = 0;
  virtual void TrackCopy(CopyCounter&& ctr) = 0;
  virtual void AllDone(void) = 0;

  virtual void NoCopyMethod(NoCopyClass& noCopy) {}
};

class SimpleSender:
  public EventSender<CallableInterface>
{
public:
  using EventSender<CallableInterface>::Fire;
  using EventSender<CallableInterface>::Defer;
};

class Jammer:
  public CoreThread,
  public EventSender<CallableInterface>
{
public:
  Jammer(void):
    totalXmit(0)
  {
    Ready();
  }

  int totalXmit;

  void Run(void) override {
    while(!ShouldStop() && totalXmit < 0x7FFFF000)
      // Jam for awhile in an asynchronous way:
      while(++totalXmit % 100)
        Fire(&CallableInterface::ZeroArgs)();
  }
};

class SimpleReceiver:
  public CoreThread,
  public CallableInterface
{
public:
  SimpleReceiver(void):
    CoreThread("SimpleReceiver"),
    m_zero(false),
    m_one(false),
    m_oneArg(0),
    m_barrierDone(false)
  {
    Ready();
  }

private:
  // Continuity signal:
  boost::condition_variable m_continueCond;
  bool m_barrierDone;

public:
  // Manifest of functions called:
  bool m_zero;

  bool m_one;
  int m_oneArg;

  // Copy operation fields:
  vector<int> m_myVec;
  CopyCounter m_myCtr;

  ///
  // Interface utility methods:
  ///
  void ZeroArgs(void) override {
    m_zero = true;
  }

  void OneArg(int arg) override {
    m_one = true;
    m_oneArg = arg;
  }

  void CopyVector(const vector<int>& vec) override {
    // Copy out the argument:
    m_myVec = vec;
  }

  void CopyVectorForwarded(vector<int>&& vec) override {
    // Copy out the argument:
    m_myVec = vec;
  }

  void TrackCopy(CopyCounter&& ctr) override {
    m_myCtr = std::forward<CopyCounter>(ctr);
  }

  void NoCopyMethod(NoCopyClass& noCopy) override {
  }

  // Trivial shutdown override
  void AllDone(void) override {
    Stop();
  }

  // Overridden here so we can hit the barrier if we're still waiting on it
  void Stop() override {
    Proceed();
    CoreThread::Stop();
  }

  /// <summary>
  /// Invoked to cause Run to continue its processing
  /// </summary>
  void Proceed(void) {
    boost::lock_guard<boost::mutex> lk(m_lock);
    if(m_barrierDone)
      return;
    m_barrierDone = true;
    m_continueCond.notify_all();
  }

  ///
  // Runs the thread
  ///
  void Run(void) override {
    {
      boost::unique_lock<boost::mutex> lk(m_lock);
      m_continueCond.wait(lk, [this] () {return m_barrierDone;});
    }
    CoreThread::Run();
  }

  // Make this method public
  using CoreThread::AcceptDispatchDelivery;
  using CoreThread::RejectDispatchDelivery;
};

EventReceiverTest::EventReceiverTest(void) {
  AutoCurrentContext ctxt;

  // Start up the context:
  ctxt->InitiateCoreThreads();
}

TEST_F(EventReceiverTest, SimpleMethodCall) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Try firing the event first:
  sender->Fire(&CallableInterface::ZeroArgs)();
  sender->Fire(&CallableInterface::OneArg)(100);

  // Verify that stuff happens even when the thread isn't running:
  EXPECT_TRUE(receiver->m_zero);
  EXPECT_TRUE(receiver->m_one);
  EXPECT_EQ(100, receiver->m_oneArg);

  // Unblock:
  receiver->Proceed();
}

TEST_F(EventReceiverTest, VerifyNoReceive) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Try to defer these calls, should not be delivered anywhere:
  sender->Defer(&CallableInterface::ZeroArgs)();
  sender->Defer(&CallableInterface::OneArg)(100);

  // Unblock:
  receiver->Proceed();

  // Allow dispatch delivery and post the quit event:
  receiver->AcceptDispatchDelivery();
  sender->Defer(&CallableInterface::AllDone)();

  // Wait:
  receiver->Wait();

  // Verify that no call was not made accidentally
  EXPECT_FALSE(receiver->m_zero) << "A zero-argument call was pended to a dispatcher not marked ready";
  EXPECT_FALSE(receiver->m_one) << "A single-argument call was pended to a dispatcher not marked ready";
}

TEST_F(EventReceiverTest, DeferredInvoke) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  // Deferred fire:
  sender->Defer(&CallableInterface::ZeroArgs)();
  sender->Defer(&CallableInterface::OneArg)(101);
  sender->Defer(&CallableInterface::AllDone)();

  // Verify that nothing is hit yet:
  EXPECT_FALSE(receiver->m_zero) << "Zero-argument call made prematurely";
  EXPECT_FALSE(receiver->m_one) << "One-argument call made prematurely";
  EXPECT_TRUE(receiver->IsRunning()) << "Receiver is terminated";

  // Unblock:
  receiver->Proceed();

  // Now wait until all events are processed:
  receiver->Wait();

  // Validate deferred firing:
  EXPECT_TRUE(receiver->m_zero) << "Zero argument call was not properly deferred";
  EXPECT_TRUE(receiver->m_one) << "Single argument call was not properly deferred";
  EXPECT_EQ(101, receiver->m_oneArg) << "Argument was not correctly propagated through a deferred call";
}

TEST_F(EventReceiverTest, NontrivialCopy) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  static const int sc_numElems = 10;

  // Create the vector we're going to copy over:
  vector<int> ascending;
  for(int i = 0; i < sc_numElems; i++)
    ascending.push_back(i);

  // Deferred fire:
  sender->Defer(&CallableInterface::CopyVector)(ascending);
  sender->Defer(&CallableInterface::AllDone)();

  // Verify that nothing is hit yet:
  EXPECT_TRUE(receiver->m_myVec.empty()) << "Event handler invoked before barrier was hit; it should have been deferred";
  EXPECT_TRUE(receiver->IsRunning()) << "Receiver is terminated";

  // Unblock:
  receiver->Proceed();

  // Now wait until all events are processed:
  receiver->Wait();

  // Validate our vectors:
  ASSERT_EQ(10, (int)receiver->m_myVec.size()) << "Receiver was not populated correctly with a vector";
  for(int i = 0; i < sc_numElems; i++)
    EXPECT_EQ(i, ascending[i]) << "Element at offset " << i << " was incorrectly copied";
}

TEST_F(EventReceiverTest, VerifyNoUnnecessaryCopies) {
  // Verify the counter correctly tracks the number of times it was copied:
  {
    CopyCounter antiRecycle;
    CopyCounter base;

    CopyCounter myCopy1 = base;
    ASSERT_EQ(1, myCopy1.m_count) << "Copy counter appears to be broken; cannot run test";

    CopyCounter myCopy2 = myCopy1;
    ASSERT_EQ(2, myCopy2.m_count) << "Secondary counter appears to be broken; cannot run test";

    // Try move construction:
    CopyCounter myCopy3(std::move(myCopy2));
    ASSERT_EQ(2, myCopy3.m_count) << "Move ctor doesn't appear to be invoked correctly";

    // Verify antirecycle:
    ASSERT_THROW(antiRecycle = myCopy2, invalid_copycounter_exception);

    // Try a move copy
    CopyCounter myCopy4;
    myCopy4 = std::move(myCopy3);
    ASSERT_EQ(2, myCopy4.m_count) << "Move assignment didn't correctly propagate the current count";
    ASSERT_THROW(antiRecycle = myCopy3, invalid_copycounter_exception);

    // Try a trivial copy:
    CopyCounter myCopy5;
    myCopy5 = myCopy4;
    ASSERT_EQ(3, myCopy5.m_count) << "Assignment operator did not increment reference count";
  }

  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  // Make our copy counter:
  CopyCounter ctr;

  // Pass the field in:
  sender->Defer(&CallableInterface::TrackCopy)(ctr);

  // Signal stop:
  sender->Defer(&CallableInterface::AllDone)();

  // Let the sender process and then wait for it before we go on:
  receiver->Proceed();
  receiver->Wait();

  // There are limitations to how few times we can copy.  At a minimum, there's one
  // copy from the the Defer call, and one again when the deferred method is passed
  // the DispatchQueue
  CopyCounter& finalCtr = receiver->m_myCtr;
  EXPECT_LE(finalCtr.m_count, 2) << "Transfer object was copied too many times";
}

TEST_F(EventReceiverTest, VerifyDescendantContextWiring) {
  // Sender goes in the parent context:
  AutoRequired<SimpleSender> sender;

  std::weak_ptr<SimpleReceiver> rcvrWeak;
  {
    std::shared_ptr<SimpleReceiver> rcvrCopy;
    {
      // Create a new descendant context and put the receiver in it:
      AutoCreateContext subCtxt;
      CurrentContextPusher pshr(subCtxt);

      // Create a new descendant event receiver that matches a parent context type and should
      // be autowired to grab events from the parent:
      AutoRequired<SimpleReceiver> rcvr;
      rcvrWeak = rcvr;
      rcvrCopy = rcvr;

      // Now we try to fire and verify it gets caught on the receiver side:
      sender->Fire(&CallableInterface::ZeroArgs)();

      // Verify that it gets caught:
      EXPECT_TRUE(rcvr->m_zero) << "Event receiver in descendant context was not properly autowired";
    }

    // Verify the reference count on the event receiver
    EXPECT_EQ(1, rcvrCopy.use_count()) << "Detected a leaked reference to an event receiver";

    // Fire the event again--shouldn't be captured by the receiver because its context is gone
    rcvrCopy->m_zero = false;
    sender->Fire(&CallableInterface::ZeroArgs)();
    EXPECT_FALSE(rcvrCopy->m_zero) << "Event receiver was still wired even after its enclosing context was removed";
  }

  // The parent context had better not be holding a reference at this point
  EXPECT_TRUE(rcvrWeak.expired()) << "Event receiver reference still being held after its context and all shared references are gone";

  // Fire the event again, this shouldn't cause anything to blow up!
  sender->Fire(&CallableInterface::ZeroArgs)();
}

TEST_F(EventReceiverTest, VerifyNoCopyCallable) {
  AutoRequired<SimpleSender> sender;
  AutoRequired<SimpleReceiver> receiver;

  NoCopyClass method;
  sender->Fire(&CallableInterface::NoCopyMethod)(method);
}

TEST_F(EventReceiverTest, PathologicalChildContextTest) {
  // Set up the jammer and receiver collections:
  AutoRequired<Jammer> jammer;

  // This by itself is sufficient to cause problems:
  for(size_t i = 0; i < 500; i++) {
    AutoCreateContext subCtxt;
    CurrentContextPusher pshr(subCtxt);
    AutoRequired<SimpleReceiver> recvr;
  }

  // Spin until the jammer has transmitted a thousand messages:
  while(jammer->totalXmit < 1000);
  jammer->Stop();
  jammer->Wait();

  // Now we begin teardown operations.  If there is an improper event receiver, this will crash hard.
  AutoCurrentContext ctxt;
  ctxt->SignalTerminate();
}

TEST_F(EventReceiverTest, PathologicalTransmitterTest) {
  // Set up the jammer and receiver collections:
  AutoRequired<Jammer> jammer;

  for(size_t i = 0; i < 5; i++) {
    AutoCreateContext subCtxt;
    CurrentContextPusher pshr(subCtxt);
    AutoRequired<SimpleReceiver> recvr;
  }

  // Spin until the jammer has transmitted a thousand messages:
  while(jammer->totalXmit < 1000);
  jammer->Stop();
  jammer->Wait();

  // Now we begin teardown operations.  If there is an improper event receiver, this will crash hard.
  AutoCurrentContext ctxt;
  ctxt->SignalTerminate();
}<commit_msg>Added a missing volatile indicator in order to prevent accidental compiler overoptimization<commit_after>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "EventReceiverTest.h"
#include "Autowiring/Autowired.h"
#include "Autowiring/CoreThread.h"
#include <boost/thread/barrier.hpp>
#include <stdexcept>
#include <vector>

using namespace std;

class invalid_copycounter_exception:
  public runtime_error
{
public:
  invalid_copycounter_exception(void):
    runtime_error("Copy counter was moved, and incorrectly reused")
  {}
};

class CopyCounter {
public:
  CopyCounter(void):
    m_count(0)
  {}

  CopyCounter(const CopyCounter& rhs):
    m_count(rhs.m_count + 1)
  {
    rhs.Check();
  }

  /// <summary>
  /// Special case move ctor, which won't increment the count
  /// </summary>
  CopyCounter(CopyCounter&& rhs):
    m_count(rhs.m_count)
  {
    rhs.Check();
    rhs.m_count = -1;
  }

  /// <summary>
  /// Destructor, which invalidates the count in a specific way to indicate use-after-free
  /// </summary>
  ~CopyCounter(void) {
    m_count = -2;
  }

  // The actual count:
  int m_count;

  // Throws an exception if this copycounter is invalid
  void Check(void) const {
    if(m_count < 0)
      throw invalid_copycounter_exception();
  }

  // Copy and move overrides
  CopyCounter& operator=(const CopyCounter& rhs) {
    rhs.Check();
    m_count = rhs.m_count + 1;
    return *this;
  }

  CopyCounter& operator=(CopyCounter&& rhs) {
    rhs.Check();
    m_count = rhs.m_count;
    rhs.m_count = -1;
    return *this;
  }
};

class NoCopyClass
{
public:
  NoCopyClass():
    m_value(100)
  {}

  explicit NoCopyClass(NoCopyClass& rhs):
    m_value(101)
  {}

  int m_value;
};

class CallableInterface:
  public EventReceiver
{
public:
  virtual void ZeroArgs(void) = 0;
  virtual void OneArg(int arg) = 0;
  virtual void CopyVector(const vector<int>& vec) = 0;
  virtual void CopyVectorForwarded(vector<int>&& vec) = 0;
  virtual void TrackCopy(CopyCounter&& ctr) = 0;
  virtual void AllDone(void) = 0;

  virtual void NoCopyMethod(NoCopyClass& noCopy) {}
};

class SimpleSender:
  public EventSender<CallableInterface>
{
public:
  using EventSender<CallableInterface>::Fire;
  using EventSender<CallableInterface>::Defer;
};

class Jammer:
  public CoreThread,
  public EventSender<CallableInterface>
{
public:
  Jammer(void):
    totalXmit(0)
  {
    Ready();
  }

  volatile int totalXmit;

  void Run(void) override {
    while(!ShouldStop() && totalXmit < 0x7FFFF000)
      // Jam for awhile in an asynchronous way:
      while(++totalXmit % 100)
        Fire(&CallableInterface::ZeroArgs)();
  }
};

class SimpleReceiver:
  public CoreThread,
  public CallableInterface
{
public:
  SimpleReceiver(void):
    CoreThread("SimpleReceiver"),
    m_zero(false),
    m_one(false),
    m_oneArg(0),
    m_barrierDone(false)
  {
    Ready();
  }

private:
  // Continuity signal:
  boost::condition_variable m_continueCond;
  bool m_barrierDone;

public:
  // Manifest of functions called:
  bool m_zero;

  bool m_one;
  int m_oneArg;

  // Copy operation fields:
  vector<int> m_myVec;
  CopyCounter m_myCtr;

  ///
  // Interface utility methods:
  ///
  void ZeroArgs(void) override {
    m_zero = true;
  }

  void OneArg(int arg) override {
    m_one = true;
    m_oneArg = arg;
  }

  void CopyVector(const vector<int>& vec) override {
    // Copy out the argument:
    m_myVec = vec;
  }

  void CopyVectorForwarded(vector<int>&& vec) override {
    // Copy out the argument:
    m_myVec = vec;
  }

  void TrackCopy(CopyCounter&& ctr) override {
    m_myCtr = std::forward<CopyCounter>(ctr);
  }

  void NoCopyMethod(NoCopyClass& noCopy) override {
  }

  // Trivial shutdown override
  void AllDone(void) override {
    Stop();
  }

  // Overridden here so we can hit the barrier if we're still waiting on it
  void Stop() override {
    Proceed();
    CoreThread::Stop();
  }

  /// <summary>
  /// Invoked to cause Run to continue its processing
  /// </summary>
  void Proceed(void) {
    boost::lock_guard<boost::mutex> lk(m_lock);
    if(m_barrierDone)
      return;
    m_barrierDone = true;
    m_continueCond.notify_all();
  }

  ///
  // Runs the thread
  ///
  void Run(void) override {
    {
      boost::unique_lock<boost::mutex> lk(m_lock);
      m_continueCond.wait(lk, [this] () {return m_barrierDone;});
    }
    CoreThread::Run();
  }

  // Make this method public
  using CoreThread::AcceptDispatchDelivery;
  using CoreThread::RejectDispatchDelivery;
};

EventReceiverTest::EventReceiverTest(void) {
  AutoCurrentContext ctxt;

  // Start up the context:
  ctxt->InitiateCoreThreads();
}

TEST_F(EventReceiverTest, SimpleMethodCall) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Try firing the event first:
  sender->Fire(&CallableInterface::ZeroArgs)();
  sender->Fire(&CallableInterface::OneArg)(100);

  // Verify that stuff happens even when the thread isn't running:
  EXPECT_TRUE(receiver->m_zero);
  EXPECT_TRUE(receiver->m_one);
  EXPECT_EQ(100, receiver->m_oneArg);

  // Unblock:
  receiver->Proceed();
}

TEST_F(EventReceiverTest, VerifyNoReceive) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Try to defer these calls, should not be delivered anywhere:
  sender->Defer(&CallableInterface::ZeroArgs)();
  sender->Defer(&CallableInterface::OneArg)(100);

  // Unblock:
  receiver->Proceed();

  // Allow dispatch delivery and post the quit event:
  receiver->AcceptDispatchDelivery();
  sender->Defer(&CallableInterface::AllDone)();

  // Wait:
  receiver->Wait();

  // Verify that no call was not made accidentally
  EXPECT_FALSE(receiver->m_zero) << "A zero-argument call was pended to a dispatcher not marked ready";
  EXPECT_FALSE(receiver->m_one) << "A single-argument call was pended to a dispatcher not marked ready";
}

TEST_F(EventReceiverTest, DeferredInvoke) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  // Deferred fire:
  sender->Defer(&CallableInterface::ZeroArgs)();
  sender->Defer(&CallableInterface::OneArg)(101);
  sender->Defer(&CallableInterface::AllDone)();

  // Verify that nothing is hit yet:
  EXPECT_FALSE(receiver->m_zero) << "Zero-argument call made prematurely";
  EXPECT_FALSE(receiver->m_one) << "One-argument call made prematurely";
  EXPECT_TRUE(receiver->IsRunning()) << "Receiver is terminated";

  // Unblock:
  receiver->Proceed();

  // Now wait until all events are processed:
  receiver->Wait();

  // Validate deferred firing:
  EXPECT_TRUE(receiver->m_zero) << "Zero argument call was not properly deferred";
  EXPECT_TRUE(receiver->m_one) << "Single argument call was not properly deferred";
  EXPECT_EQ(101, receiver->m_oneArg) << "Argument was not correctly propagated through a deferred call";
}

TEST_F(EventReceiverTest, NontrivialCopy) {
  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  static const int sc_numElems = 10;

  // Create the vector we're going to copy over:
  vector<int> ascending;
  for(int i = 0; i < sc_numElems; i++)
    ascending.push_back(i);

  // Deferred fire:
  sender->Defer(&CallableInterface::CopyVector)(ascending);
  sender->Defer(&CallableInterface::AllDone)();

  // Verify that nothing is hit yet:
  EXPECT_TRUE(receiver->m_myVec.empty()) << "Event handler invoked before barrier was hit; it should have been deferred";
  EXPECT_TRUE(receiver->IsRunning()) << "Receiver is terminated";

  // Unblock:
  receiver->Proceed();

  // Now wait until all events are processed:
  receiver->Wait();

  // Validate our vectors:
  ASSERT_EQ(10, (int)receiver->m_myVec.size()) << "Receiver was not populated correctly with a vector";
  for(int i = 0; i < sc_numElems; i++)
    EXPECT_EQ(i, ascending[i]) << "Element at offset " << i << " was incorrectly copied";
}

TEST_F(EventReceiverTest, VerifyNoUnnecessaryCopies) {
  // Verify the counter correctly tracks the number of times it was copied:
  {
    CopyCounter antiRecycle;
    CopyCounter base;

    CopyCounter myCopy1 = base;
    ASSERT_EQ(1, myCopy1.m_count) << "Copy counter appears to be broken; cannot run test";

    CopyCounter myCopy2 = myCopy1;
    ASSERT_EQ(2, myCopy2.m_count) << "Secondary counter appears to be broken; cannot run test";

    // Try move construction:
    CopyCounter myCopy3(std::move(myCopy2));
    ASSERT_EQ(2, myCopy3.m_count) << "Move ctor doesn't appear to be invoked correctly";

    // Verify antirecycle:
    ASSERT_THROW(antiRecycle = myCopy2, invalid_copycounter_exception);

    // Try a move copy
    CopyCounter myCopy4;
    myCopy4 = std::move(myCopy3);
    ASSERT_EQ(2, myCopy4.m_count) << "Move assignment didn't correctly propagate the current count";
    ASSERT_THROW(antiRecycle = myCopy3, invalid_copycounter_exception);

    // Try a trivial copy:
    CopyCounter myCopy5;
    myCopy5 = myCopy4;
    ASSERT_EQ(3, myCopy5.m_count) << "Assignment operator did not increment reference count";
  }

  AutoRequired<SimpleReceiver> receiver;
  AutoRequired<SimpleSender> sender;

  // Accept dispatch delivery:
  receiver->AcceptDispatchDelivery();

  // Make our copy counter:
  CopyCounter ctr;

  // Pass the field in:
  sender->Defer(&CallableInterface::TrackCopy)(ctr);

  // Signal stop:
  sender->Defer(&CallableInterface::AllDone)();

  // Let the sender process and then wait for it before we go on:
  receiver->Proceed();
  receiver->Wait();

  // There are limitations to how few times we can copy.  At a minimum, there's one
  // copy from the the Defer call, and one again when the deferred method is passed
  // the DispatchQueue
  CopyCounter& finalCtr = receiver->m_myCtr;
  EXPECT_LE(finalCtr.m_count, 2) << "Transfer object was copied too many times";
}

TEST_F(EventReceiverTest, VerifyDescendantContextWiring) {
  // Sender goes in the parent context:
  AutoRequired<SimpleSender> sender;

  std::weak_ptr<SimpleReceiver> rcvrWeak;
  {
    std::shared_ptr<SimpleReceiver> rcvrCopy;
    {
      // Create a new descendant context and put the receiver in it:
      AutoCreateContext subCtxt;
      CurrentContextPusher pshr(subCtxt);

      // Create a new descendant event receiver that matches a parent context type and should
      // be autowired to grab events from the parent:
      AutoRequired<SimpleReceiver> rcvr;
      rcvrWeak = rcvr;
      rcvrCopy = rcvr;

      // Now we try to fire and verify it gets caught on the receiver side:
      sender->Fire(&CallableInterface::ZeroArgs)();

      // Verify that it gets caught:
      EXPECT_TRUE(rcvr->m_zero) << "Event receiver in descendant context was not properly autowired";
    }

    // Verify the reference count on the event receiver
    EXPECT_EQ(1, rcvrCopy.use_count()) << "Detected a leaked reference to an event receiver";

    // Fire the event again--shouldn't be captured by the receiver because its context is gone
    rcvrCopy->m_zero = false;
    sender->Fire(&CallableInterface::ZeroArgs)();
    EXPECT_FALSE(rcvrCopy->m_zero) << "Event receiver was still wired even after its enclosing context was removed";
  }

  // The parent context had better not be holding a reference at this point
  EXPECT_TRUE(rcvrWeak.expired()) << "Event receiver reference still being held after its context and all shared references are gone";

  // Fire the event again, this shouldn't cause anything to blow up!
  sender->Fire(&CallableInterface::ZeroArgs)();
}

TEST_F(EventReceiverTest, VerifyNoCopyCallable) {
  AutoRequired<SimpleSender> sender;
  AutoRequired<SimpleReceiver> receiver;

  NoCopyClass method;
  sender->Fire(&CallableInterface::NoCopyMethod)(method);
}

TEST_F(EventReceiverTest, PathologicalChildContextTest) {
  // Set up the jammer and receiver collections:
  AutoRequired<Jammer> jammer;

  // This by itself is sufficient to cause problems:
  for(size_t i = 0; i < 500; i++) {
    AutoCreateContext subCtxt;
    CurrentContextPusher pshr(subCtxt);
    AutoRequired<SimpleReceiver> recvr;
  }

  // Spin until the jammer has transmitted a thousand messages:
  while(jammer->totalXmit < 1000);
  jammer->Stop();
  jammer->Wait();

  // Now we begin teardown operations.  If there is an improper event receiver, this will crash hard.
  AutoCurrentContext ctxt;
  ctxt->SignalTerminate();
}

TEST_F(EventReceiverTest, PathologicalTransmitterTest) {
  // Set up the jammer and receiver collections:
  AutoRequired<Jammer> jammer;

  for(size_t i = 0; i < 5; i++) {
    AutoCreateContext subCtxt;
    CurrentContextPusher pshr(subCtxt);
    AutoRequired<SimpleReceiver> recvr;
  }

  // Spin until the jammer has transmitted a thousand messages:
  while(jammer->totalXmit < 1000);
  jammer->Stop();
  jammer->Wait();

  // Now we begin teardown operations.  If there is an improper event receiver, this will crash hard.
  AutoCurrentContext ctxt;
  ctxt->SignalTerminate();
}<|endoftext|>


<commit_before>/*
* Copyright (c)  2005, Stanford University. All rights reserved.
* Use of the OpenSim software in source form is permitted provided that the following
* conditions are met:
* 	1. The software is used only for non-commercial research and education. It may not
*     be used in relation to any commercial activity.
* 	2. The software is not distributed or redistributed.  Software distribution is allowed
*     only through https://simtk.org/home/opensim.
* 	3. Use of the OpenSim software or derivatives must be acknowledged in all publications,
*      presentations, or documents describing work in which OpenSim or derivatives are used.
* 	4. Credits to developers may not be removed from executables
*     created from modifications of the source.
* 	5. Modifications of source code must retain the above copyright notice, this list of
*     conditions and the following disclaimer.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
*  SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR BUSINESS INTERRUPTION) OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
*  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// forward.cpp
// author:  Frank C. Anderson, Ajay Seth

// INCLUDE
#include <string>
#include <iostream>
#include <OpenSim/Simulation/Control/Controller.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Simulation/Model/LoadModel.h>
#include <OpenSim/Simulation/Model/AnalysisSet.h>
#include <OpenSim/Tools/ForwardTool.h>
#include <OpenSim/Analyses/Kinematics.h>
#include <OpenSim/Analyses/Actuation.h>
#include <OpenSim/Analyses/PointKinematics.h>
#include <OpenSim/Analyses/BodyKinematics.h>

using namespace OpenSim;
using namespace std;

#define ASSERT(cond) {if (!(cond)) throw(exception());}
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) throw(exception());}

/*
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) printf("ASSERT_EQUAL FAILED expected=%f found=%f\n", expected,found);}

*/
#define ASSERT_EQUAL_STATE(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) {  \
			printf(" ASSERT_EQUAL FAILED t=%f state# %d %s std=%f  computed=%f \n", time, j, standard->getColumnLabels()[j+1].c_str(), data[j], state->getData()[j] ) ; \
            failed = true;  \
 } else { \
			printf(" ASSERT_EQUAL PASSED t=%f state# %d %s std=%f  computed=%f \n", time, j, standard->getColumnLabels()[j+1].c_str(), data[j], state->getData()[j] ) ; \
} }

void testPendulum() {
	ForwardTool forward("setup_pend.xml");
	forward.run();
	forward.print("check.xml");
	Storage storage("Results/pendulum_states.sto");
	ASSERT(storage.getFirstTime() == 0.0);
	ASSERT(storage.getLastTime() == 1.0);
	ASSERT(storage.getSize() > 10);

	// Since the pendulum is only swinging through small angles, it should be very
	// close to a simple harmonic oscillator.

	double previousTime = -1.0;
	double k = std::sqrt(9.80665000/0.5);
	for (int j = 0; j < storage.getSize(); ++j) {
		StateVector* state = storage.getStateVector(j);
		double time = state->getTime();
		ASSERT(time > previousTime);
		previousTime = time;
		ASSERT_EQUAL(0.1*std::cos(k*time), state->getData()[0], 1.5e-3);
		ASSERT_EQUAL(0.0, state->getData()[1], 1e-5);
		ASSERT_EQUAL(0.0, state->getData()[2], 1e-5);
		ASSERT_EQUAL(-k*0.1*std::sin(k*time), state->getData()[3], 1.5e-3);
		ASSERT_EQUAL(0.0, state->getData()[4], 1e-5);
		ASSERT_EQUAL(0.0, state->getData()[5], 1e-5);
	}
	ASSERT(previousTime == 1.0);
}

void testArm26() {
    bool failed = false;
	ForwardTool forward("arm26_Setup_Forward.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("Results/arm26_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("std_arm26_states.sto");
    forward.loadStatesStorage( statesFileName, standard );
	StateVector* state = results.getStateVector(0);
	double time = state->getTime();
	Array<double> data;
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	for (int j = 0; j < state->getSize(); ++j) {
        ASSERT_EQUAL_STATE(data[j], state->getData()[j], 2.5e-3);
    }

	int i = results.getSize()-1;
    state = results.getStateVector(i);
    time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	for (int j = 0; j < state->getSize(); ++j) {
        ASSERT_EQUAL_STATE(data[j], state->getData()[j], 2.5e-3);
	}
    if( failed ) throw(exception());
}

void testGait2354() {
    bool failed = false;
	//ExternalLoads ext;
	//ext.print("ExternalLoads.xml");
	ForwardTool forward("setup_gait2354.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("Results/gait2354_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("std_gait2354_states.sto");
    forward.loadStatesStorage( statesFileName, standard );

	Array<double> data;
	StateVector* state = results.getStateVector(0);
	double time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);

	// At initial time all states should be identical except for locked joints may vary slightly due to
	// differences in OpenSim's integrator and SimTK's
	int nc = forward.getModel().getNumCoordinates();
	for (int j = 0; j < state->getSize(); ++j) {
		ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-2);
	}

	int i = results.getSize()-1;
	state = results.getStateVector(i);
	time = state->getTime();
	standard->getDataAtTime(time, state->getSize(), data);

	// NOTE: Gait model is running forward open-loop. We cannot expect all the states to
	// be "bang on" and we expect a gradual drift in the coordinates.  Check to see that
	// coordinates haven't drifted too far off.
	for (int j = 0; j < nc; ++j) {
	    ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-1);
	}

    if( failed ) throw(exception());
}

void testGait2354WithController() {
    bool failed = false;
	ForwardTool forward("subject01_Setup_Forward_Controller.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("ResultsSimpleFeedbackController/subject01_walk1_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("subject01_walk1_states.sto");
    forward.loadStatesStorage( statesFileName, standard );

	Array<double> data;
	int i = results.getSize() - 1;
	StateVector* state = results.getStateVector(i);
	double time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	int nc = forward.getModel().getNumCoordinates();
	for (int j = 0; j < nc; ++j) {
	    ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-2);
	}
    if( failed ) throw(exception());

}

int main() {
    try {

        testPendulum();	// test manager/integration process
		std::cout << "Pendulum test PASSED " << std::endl;

		testArm26();	// now add computation of controls and generation of muscle forces
		std::cout << "arm26 test PASSED " << std::endl;

		testGait2354();    //finally include applied ground reactions forces
		std::cout << "gait2354 test PASSED " << std::endl;

		testGait2354WithController();
		std::cout << "gait2354 with correction controller test PASSED " << std::endl;
	}
    catch(const std::exception& e) {
        cout << "exception: " << e.what() << endl;
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}
<commit_msg>Replaced printf's with cout. printf was causing a segfault on VC10.<commit_after>/*
* Copyright (c)  2005, Stanford University. All rights reserved.
* Use of the OpenSim software in source form is permitted provided that the following
* conditions are met:
* 	1. The software is used only for non-commercial research and education. It may not
*     be used in relation to any commercial activity.
* 	2. The software is not distributed or redistributed.  Software distribution is allowed
*     only through https://simtk.org/home/opensim.
* 	3. Use of the OpenSim software or derivatives must be acknowledged in all publications,
*      presentations, or documents describing work in which OpenSim or derivatives are used.
* 	4. Credits to developers may not be removed from executables
*     created from modifications of the source.
* 	5. Modifications of source code must retain the above copyright notice, this list of
*     conditions and the following disclaimer.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
*  SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR BUSINESS INTERRUPTION) OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
*  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// forward.cpp
// author:  Frank C. Anderson, Ajay Seth

// INCLUDE
#include <string>
#include <iostream>
#include <OpenSim/Simulation/Control/Controller.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Simulation/Model/LoadModel.h>
#include <OpenSim/Simulation/Model/AnalysisSet.h>
#include <OpenSim/Tools/ForwardTool.h>
#include <OpenSim/Analyses/Kinematics.h>
#include <OpenSim/Analyses/Actuation.h>
#include <OpenSim/Analyses/PointKinematics.h>
#include <OpenSim/Analyses/BodyKinematics.h>

using namespace OpenSim;
using namespace std;

#define ASSERT(cond) {if (!(cond)) throw(exception());}
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) throw(exception());}

/*
#define ASSERT_EQUAL(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) printf("ASSERT_EQUAL FAILED expected=%f found=%f\n", expected,found);}

*/
#define ASSERT_EQUAL_STATE(expected, found, tolerance) {double tol = std::max((tolerance), std::abs((expected)*(tolerance))); if ((found)<(expected)-(tol) || (found)>(expected)+(tol)) {  \
			cout << "ASSERT_EQUAL FAILED t="<< time <<" state# "<<j << " " << standard->getColumnLabels()[j+1] << " std=" << data[j] <<"  computed=" << state->getData()[j]  << endl ; \
            failed = true;  \
 } else { \
			cout << "ASSERT_EQUAL PASSED t="<< time <<" state# "<<j << " " << standard->getColumnLabels()[j+1] << " std=" << data[j] <<"  computed=" << state->getData()[j]  << endl ; \
} }

void testPendulum() {
	ForwardTool forward("setup_pend.xml");
	forward.run();
	forward.print("check.xml");
	Storage storage("Results/pendulum_states.sto");
	ASSERT(storage.getFirstTime() == 0.0);
	ASSERT(storage.getLastTime() == 1.0);
	ASSERT(storage.getSize() > 10);

	// Since the pendulum is only swinging through small angles, it should be very
	// close to a simple harmonic oscillator.

	double previousTime = -1.0;
	double k = std::sqrt(9.80665000/0.5);
	for (int j = 0; j < storage.getSize(); ++j) {
		StateVector* state = storage.getStateVector(j);
		double time = state->getTime();
		ASSERT(time > previousTime);
		previousTime = time;
		ASSERT_EQUAL(0.1*std::cos(k*time), state->getData()[0], 1.5e-3);
		ASSERT_EQUAL(0.0, state->getData()[1], 1e-5);
		ASSERT_EQUAL(0.0, state->getData()[2], 1e-5);
		ASSERT_EQUAL(-k*0.1*std::sin(k*time), state->getData()[3], 1.5e-3);
		ASSERT_EQUAL(0.0, state->getData()[4], 1e-5);
		ASSERT_EQUAL(0.0, state->getData()[5], 1e-5);
	}
	ASSERT(previousTime == 1.0);
}

void testArm26() {
    bool failed = false;
	ForwardTool forward("arm26_Setup_Forward.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("Results/arm26_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("std_arm26_states.sto");
    forward.loadStatesStorage( statesFileName, standard );
	StateVector* state = results.getStateVector(0);
	double time = state->getTime();
	Array<double> data;
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	for (int j = 0; j < state->getSize(); ++j) {
        ASSERT_EQUAL_STATE(data[j], state->getData()[j], 2.5e-3);
    }

	int i = results.getSize()-1;
    state = results.getStateVector(i);
    time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	for (int j = 0; j < state->getSize(); ++j) {
        ASSERT_EQUAL_STATE(data[j], state->getData()[j], 2.5e-3);
	}
    if( failed ) throw(exception());
}

void testGait2354() {
    bool failed = false;
	//ExternalLoads ext;
	//ext.print("ExternalLoads.xml");
	ForwardTool forward("setup_gait2354.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("Results/gait2354_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("std_gait2354_states.sto");
    forward.loadStatesStorage( statesFileName, standard );

	Array<double> data;
	StateVector* state = results.getStateVector(0);
	double time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);

	// At initial time all states should be identical except for locked joints may vary slightly due to
	// differences in OpenSim's integrator and SimTK's
	int nc = forward.getModel().getNumCoordinates();
	for (int j = 0; j < state->getSize(); ++j) {
		ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-2);
	}

	int i = results.getSize()-1;
	state = results.getStateVector(i);
	time = state->getTime();
	standard->getDataAtTime(time, state->getSize(), data);

	// NOTE: Gait model is running forward open-loop. We cannot expect all the states to
	// be "bang on" and we expect a gradual drift in the coordinates.  Check to see that
	// coordinates haven't drifted too far off.
	for (int j = 0; j < nc; ++j) {
	    ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-1);
	}

    if( failed ) throw(exception());
}

void testGait2354WithController() {
    bool failed = false;
	ForwardTool forward("subject01_Setup_Forward_Controller.xml");
	forward.run();
	forward.print("check.xml");
	Storage results("ResultsSimpleFeedbackController/subject01_walk1_states.sto");
	Storage* standard = new Storage();
    std::string statesFileName("subject01_walk1_states.sto");
    forward.loadStatesStorage( statesFileName, standard );

	Array<double> data;
	int i = results.getSize() - 1;
	StateVector* state = results.getStateVector(i);
	double time = state->getTime();
	data.setSize(state->getSize());
	standard->getDataAtTime(time, state->getSize(), data);
	int nc = forward.getModel().getNumCoordinates();
	for (int j = 0; j < nc; ++j) {
	    ASSERT_EQUAL_STATE(data[j], state->getData()[j], 5e-2);
	}
    if( failed ) throw(exception());

}

int main() {
    try {

        testPendulum();	// test manager/integration process
		std::cout << "Pendulum test PASSED " << std::endl;

		testArm26();	// now add computation of controls and generation of muscle forces
		std::cout << "arm26 test PASSED " << std::endl;

		testGait2354();    //finally include applied ground reactions forces
		std::cout << "gait2354 test PASSED " << std::endl;

		testGait2354WithController();
		std::cout << "gait2354 with correction controller test PASSED " << std::endl;
	}
    catch(const std::exception& e) {
        cout << "exception: " << e.what() << endl;
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}
<|endoftext|>