<commit_before>// Bindings
#include "PyROOT.h"
#include "Adapters.h"
#include "Utility.h"

// ROOT
#include "TBaseClass.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TDataType.h"
#include "TDataMember.h"
#include "TMethod.h"
#include "TFunction.h"
#include "TMethodArg.h"
#include "TList.h"
#include "TError.h"

// CINT
#include "Api.h"

//= TReturnTypeAdapter =======================================================
std::string PyROOT::TReturnTypeAdapter::Name( unsigned int mod ) const
{
// get the name of the return type that is being adapted
   std::string name = fName;

   if ( ! ( mod & Rflx::QUALIFIED ) )
      name = TClassEdit::CleanType( fName.c_str(), 1 );

   if ( mod & Rflx::FINAL )
      name = Utility::ResolveTypedef( name );

   return name;
}

//= TMemberAdapter ===========================================================
PyROOT::TMemberAdapter::TMemberAdapter( TMethod* meth ) : fMember( meth )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TMethod*() const
{
// cast the adapter to a TMethod* being adapted, returns 0 on failure
   return dynamic_cast< TMethod* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TFunction* func ) : fMember( func )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TFunction*() const
{
// cast the adapter to a TFunction* being adapted, returns 0 on failure
   return dynamic_cast< TFunction* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TDataMember* mb ) : fMember( mb )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TDataMember*() const
{
// cast the adapter to a TDataMember* being adapted, returns 0 on failure
   return dynamic_cast< TDataMember* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TMethodArg* ma ) : fMember( ma )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TMethodArg*() const
{
// cast the adapter to a TMethodArg* being adapted, returns 0 on failure
   return dynamic_cast< TMethodArg* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::Name( unsigned int mod ) const
{
// Return name of the type described by fMember
   TMethodArg* arg = (TMethodArg*)*this;

   if ( arg ) {

      std::string name = arg->GetTypeName();
      if ( mod & Rflx::QUALIFIED )
         name = arg->GetFullTypeName();

      if ( mod & Rflx::FINAL )
         name = Utility::ResolveTypedef( name );

      return name;

   } else if ( mod & Rflx::FINAL )
      return Utility::ResolveTypedef( fMember->GetName() );

// new with cling, TMethod names are fully scoped ...
   TMethod* m = (TMethod*)*this;
   if (m && m->GetClass()) {
      std::string scoped_name = m->GetName();
      std::string class_name = m->GetClass()->GetName();
      std::string::size_type pos = scoped_name.find(class_name + "::");
      if (pos == 0)      // only accept found at start
         return scoped_name.substr(class_name.size() + 2 /* for :: */, std::string::npos);
   }

   return fMember->GetName();
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsEnum() const
{
// test if the adapted member is of an enum type
   return fMember->Property() & kIsEnum;
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsPublic() const
{
// test if the adapted member represents an public (data) member
   return fMember->Property() & kIsPublic;
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsStatic() const
{
// test if the adapted member represents a class (data) member
   return fMember->Property() & G__BIT_ISSTATIC;
}

//____________________________________________________________________________
size_t PyROOT::TMemberAdapter::FunctionParameterSize( Bool_t required ) const
{
// get the total number of parameters that the adapted function/method takes
   TFunction* func = (TFunction*)fMember;
   if ( ! func )
      return 0;

   if ( required == true )
      return func->GetNargs() - func->GetNargsOpt();

   return func->GetNargs();
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TMemberAdapter::FunctionParameterAt( size_t nth ) const
{
// get the type info of the function parameter at position nth
   return (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth );
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::FunctionParameterNameAt( size_t nth ) const
{
// get the formal name, if available, of the function parameter at position nth
   const char* name =
      ((TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth ))->GetName();

   if ( name )
      return name;
   return "";
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::FunctionParameterDefaultAt( size_t nth ) const
{
// get the default value, if available, of the function parameter at position nth
   TMethodArg* arg = (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth );
   const char* def = arg->GetDefault();

   if ( ! def )
      return "";

// special case for strings: "some value" -> ""some value"
   if ( strstr( Utility::ResolveTypedef( arg->GetTypeName() ).c_str(), "char*" ) ) {
      std::string sdef = "\"";
      sdef += def;
      sdef += "\"";
      return sdef;
   }

   return def;
}

//____________________________________________________________________________
PyROOT::TReturnTypeAdapter PyROOT::TMemberAdapter::ReturnType() const
{
// get the return type of the wrapped function/method
   return TReturnTypeAdapter( ((TFunction*)fMember)->GetReturnTypeName() );
}

//____________________________________________________________________________
PyROOT::TScopeAdapter PyROOT::TMemberAdapter::DeclaringScope() const
{
// get the declaring scope (class) of the wrapped function/method
   TMethod* method = (TMethod*)*this;
   if ( method )
      return method->GetClass();

// happens for free-standing functions (i.e. global scope)
   return std::string( "" );
}

//= TBaseAdapter =============================================================
std::string PyROOT::TBaseAdapter::Name() const
{
// get the name of the base class that is being adapted
   return fBase->GetName();
}

//= TScopeAdapter ============================================================
PyROOT::TScopeAdapter::TScopeAdapter( TClass* klass ) : fClass( klass )
{
// wrap a class (scope)
   if ( fClass.GetClass() != 0 )
      fName = fClass->GetName();
}

//____________________________________________________________________________
PyROOT::TScopeAdapter::TScopeAdapter( const std::string& name ) :
   fClass( name.c_str() ), fName( name )
{
   /* empty */
}

PyROOT::TScopeAdapter::TScopeAdapter( const TMemberAdapter& mb ) :
      fClass( mb.Name( Rflx::SCOPED ).c_str() ),
      fName( mb.Name( Rflx::QUALIFIED | Rflx::SCOPED ) )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TScopeAdapter PyROOT::TScopeAdapter::ByName( const std::string& name, Bool_t quiet )
{
// lookup a scope (class) by name
   Int_t oldEIL = gErrorIgnoreLevel;
   if ( quiet )
      gErrorIgnoreLevel = 3000;
   TClass* klass = TClass::GetClass( name.c_str() );
   gErrorIgnoreLevel = oldEIL;

   return klass;
}

//____________________________________________________________________________
std::string PyROOT::TScopeAdapter::Name( unsigned int mod ) const
{
// Return name of type described by fClass
   if ( ! fClass.GetClass() || ! fClass->Property() ) {
   // fundamental types have no class, and unknown classes have no property
      std::string name = fName;

      if ( ! ( mod & Rflx::QUALIFIED ) )
         name = TClassEdit::CleanType( fName.c_str(), 1 );

      if ( mod & Rflx::FINAL )
         name = Utility::ResolveTypedef( name );

      return name;
   }

   if ( mod & Rflx::FINAL ) {
   /* The following G__ClassInfo lookup is badly broken ...
      G__ClassInfo* clInfo = (G__ClassInfo*)fClass->GetClassInfo();
      if ( mod & Rflx::SCOPED )
         return (clInfo && clInfo->Fullname()) ? clInfo->Fullname() : fClass->GetName();

   // unscoped name ...
      std::string actual = (clInfo && clInfo->Name()) ? clInfo->Name() : fClass->GetName();

   // in case of missing dictionaries, the scope won't have been stripped
      if ( ! ( clInfo && clInfo->IsValid() ) ) {
         std::string::size_type pos = actual.substr( 0, actual.find( '<' ) ).rfind( "::" );
         if ( pos != std::string::npos ) {
         // this is somewhat of a gamble, but the alternative is a guaranteed crash
            actual = actual.substr( pos + 2, std::string::npos );
         }
      }

      return actual;
   */
      return fClass->GetName();

   } else if ( ! ( mod & Rflx::SCOPED ) ) {
   /* The following G__ClassInfo lookup is badly broken ...
      G__ClassInfo* clInfo = (G__ClassInfo*)fClass->GetClassInfo();
      return (clInfo && clInfo->Name()) ? clInfo->Name() : fClass->GetName();
   */
      return fClass->GetName();
   }

   return fClass->GetName();
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::BaseSize() const
{
// get the total number of base classes that this class has
   if ( fClass.GetClass() && fClass->GetListOfBases() != 0 )
      return fClass->GetListOfBases()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TBaseAdapter PyROOT::TScopeAdapter::BaseAt( size_t nth ) const
{
// get the nth base of this class
   return (TBaseClass*)fClass->GetListOfBases()->At( nth );
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::FunctionMemberSize() const
{
// get the total number of methods that this class has
   if ( fClass.GetClass() )
      return fClass->GetListOfMethods()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TScopeAdapter::FunctionMemberAt( size_t nth ) const
{
// get the nth method of this class
   return (TMethod*)fClass->GetListOfMethods()->At( nth );
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::DataMemberSize() const
{
// get the total number of data members that this class has
   if ( fClass.GetClass() )
      return fClass->GetListOfDataMembers()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TScopeAdapter::DataMemberAt( size_t nth ) const
{
// get the nth data member of this class
   return (TDataMember*)fClass->GetListOfDataMembers()->At( nth );
}

//____________________________________________________________________________
PyROOT::TScopeAdapter::operator Bool_t() const
{
// check the validity of this scope (class)
   if ( fName.empty() )
      return false;

   Int_t oldEIL = gErrorIgnoreLevel;
   gErrorIgnoreLevel = 3000;
   Bool_t b = G__TypeInfo( Name( Rflx::QUALIFIED | Rflx::SCOPED ).c_str() ).IsValid();
   gErrorIgnoreLevel = oldEIL;
   return b;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsComplete() const
{
// verify whether the dictionary of this class is fully available
   return G__TypeInfo( Name( Rflx::SCOPED ).c_str() ).IsLoaded();
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsClass() const
{
// test if this scope represents a class
   if ( fClass.GetClass() ) {
   // some inverted logic: we don't have a TClass, but a builtin will be recognized, so
   // if it is NOT a builtin, it is a class or struct (but may be missing dictionary)
      return (fClass->Property() & kIsClass) || ! (fClass->Property() & kIsFundamental);
   }

// no class can mean either is no class (i.e. builtin), or no dict but coming in
// through PyCintex/Reflex ... as a workaround, use TDataTypes that has a full
// enumeration of builtin types
   return TDataType( Name( Rflx::FINAL | Rflx::SCOPED ).c_str() ).GetType() == kOther_t;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsStruct() const
{
// test if this scope represents a struct
   if ( fClass.GetClass() ) {
   // same logic as for IsClass() above ...
      return (fClass->Property() & kIsStruct) || ! (fClass->Property() & kIsFundamental);
   }

// same logic as for IsClass() above ...
   return TDataType( Name( Rflx::FINAL | Rflx::SCOPED ).c_str() ).GetType() == kOther_t;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsNamespace() const
{
// test if this scope represents a namespace
   if ( fClass.GetClass() )
      return fClass->Property() & G__BIT_ISNAMESPACE;

   return kFALSE;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsAbstract() const
{
// test if this scope represents an abstract class
   if ( fClass.GetClass() )
      return fClass->Property() & kIsAbstract;   // assume set only for classes

   return kFALSE;
}
<commit_msg>more CINT removal<commit_after>// Bindings
#include "PyROOT.h"
#include "Adapters.h"
#include "Utility.h"

// ROOT
#include "TInterpreter.h"
#include "TBaseClass.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TDataType.h"
#include "TDataMember.h"
#include "TMethod.h"
#include "TFunction.h"
#include "TMethodArg.h"
#include "TList.h"
#include "TError.h"

//= TReturnTypeAdapter =======================================================
std::string PyROOT::TReturnTypeAdapter::Name( unsigned int mod ) const
{
// get the name of the return type that is being adapted
   std::string name = fName;

   if ( ! ( mod & Rflx::QUALIFIED ) )
      name = TClassEdit::CleanType( fName.c_str(), 1 );

   if ( mod & Rflx::FINAL )
      name = Utility::ResolveTypedef( name );

   return name;
}

//= TMemberAdapter ===========================================================
PyROOT::TMemberAdapter::TMemberAdapter( TMethod* meth ) : fMember( meth )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TMethod*() const
{
// cast the adapter to a TMethod* being adapted, returns 0 on failure
   return dynamic_cast< TMethod* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TFunction* func ) : fMember( func )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TFunction*() const
{
// cast the adapter to a TFunction* being adapted, returns 0 on failure
   return dynamic_cast< TFunction* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TDataMember* mb ) : fMember( mb )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TDataMember*() const
{
// cast the adapter to a TDataMember* being adapted, returns 0 on failure
   return dynamic_cast< TDataMember* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::TMemberAdapter( TMethodArg* ma ) : fMember( ma )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TMemberAdapter::operator TMethodArg*() const
{
// cast the adapter to a TMethodArg* being adapted, returns 0 on failure
   return dynamic_cast< TMethodArg* >( const_cast< TDictionary* >( fMember ) );
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::Name( unsigned int mod ) const
{
// Return name of the type described by fMember
   TMethodArg* arg = (TMethodArg*)*this;

   if ( arg ) {

      std::string name = arg->GetTypeName();
      if ( mod & Rflx::QUALIFIED )
         name = arg->GetFullTypeName();

      if ( mod & Rflx::FINAL )
         name = Utility::ResolveTypedef( name );

      return name;

   } else if ( mod & Rflx::FINAL )
      return Utility::ResolveTypedef( fMember->GetName() );

// new with cling, TMethod names are fully scoped ...
   TMethod* m = (TMethod*)*this;
   if (m && m->GetClass()) {
      std::string scoped_name = m->GetName();
      std::string class_name = m->GetClass()->GetName();
      std::string::size_type pos = scoped_name.find(class_name + "::");
      if (pos == 0)      // only accept found at start
         return scoped_name.substr(class_name.size() + 2 /* for :: */, std::string::npos);
   }

   return fMember->GetName();
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsEnum() const
{
// test if the adapted member is of an enum type
   return fMember->Property() & kIsEnum;
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsPublic() const
{
// test if the adapted member represents an public (data) member
   return fMember->Property() & kIsPublic;
}

//____________________________________________________________________________
Bool_t PyROOT::TMemberAdapter::IsStatic() const
{
// test if the adapted member represents a class (data) member
   return fMember->Property() & G__BIT_ISSTATIC;
}

//____________________________________________________________________________
size_t PyROOT::TMemberAdapter::FunctionParameterSize( Bool_t required ) const
{
// get the total number of parameters that the adapted function/method takes
   TFunction* func = (TFunction*)fMember;
   if ( ! func )
      return 0;

   if ( required == true )
      return func->GetNargs() - func->GetNargsOpt();

   return func->GetNargs();
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TMemberAdapter::FunctionParameterAt( size_t nth ) const
{
// get the type info of the function parameter at position nth
   return (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth );
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::FunctionParameterNameAt( size_t nth ) const
{
// get the formal name, if available, of the function parameter at position nth
   const char* name =
      ((TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth ))->GetName();

   if ( name )
      return name;
   return "";
}

//____________________________________________________________________________
std::string PyROOT::TMemberAdapter::FunctionParameterDefaultAt( size_t nth ) const
{
// get the default value, if available, of the function parameter at position nth
   TMethodArg* arg = (TMethodArg*)((TFunction*)fMember)->GetListOfMethodArgs()->At( nth );
   const char* def = arg->GetDefault();

   if ( ! def )
      return "";

// special case for strings: "some value" -> ""some value"
   if ( strstr( Utility::ResolveTypedef( arg->GetTypeName() ).c_str(), "char*" ) ) {
      std::string sdef = "\"";
      sdef += def;
      sdef += "\"";
      return sdef;
   }

   return def;
}

//____________________________________________________________________________
PyROOT::TReturnTypeAdapter PyROOT::TMemberAdapter::ReturnType() const
{
// get the return type of the wrapped function/method
   return TReturnTypeAdapter( ((TFunction*)fMember)->GetReturnTypeName() );
}

//____________________________________________________________________________
PyROOT::TScopeAdapter PyROOT::TMemberAdapter::DeclaringScope() const
{
// get the declaring scope (class) of the wrapped function/method
   TMethod* method = (TMethod*)*this;
   if ( method )
      return method->GetClass();

// happens for free-standing functions (i.e. global scope)
   return std::string( "" );
}

//= TBaseAdapter =============================================================
std::string PyROOT::TBaseAdapter::Name() const
{
// get the name of the base class that is being adapted
   return fBase->GetName();
}

//= TScopeAdapter ============================================================
PyROOT::TScopeAdapter::TScopeAdapter( TClass* klass ) : fClass( klass )
{
// wrap a class (scope)
   if ( fClass.GetClass() != 0 )
      fName = fClass->GetName();
}

//____________________________________________________________________________
PyROOT::TScopeAdapter::TScopeAdapter( const std::string& name ) :
   fClass( name.c_str() ), fName( name )
{
   /* empty */
}

PyROOT::TScopeAdapter::TScopeAdapter( const TMemberAdapter& mb ) :
      fClass( mb.Name( Rflx::SCOPED ).c_str() ),
      fName( mb.Name( Rflx::QUALIFIED | Rflx::SCOPED ) )
{
   /* empty */
}

//____________________________________________________________________________
PyROOT::TScopeAdapter PyROOT::TScopeAdapter::ByName( const std::string& name, Bool_t quiet )
{
// lookup a scope (class) by name
   Int_t oldEIL = gErrorIgnoreLevel;
   if ( quiet )
      gErrorIgnoreLevel = 3000;
   TClass* klass = TClass::GetClass( name.c_str() );
   gErrorIgnoreLevel = oldEIL;

   return klass;
}

//____________________________________________________________________________
std::string PyROOT::TScopeAdapter::Name( unsigned int mod ) const
{
// Return name of type described by fClass
   if ( ! fClass.GetClass() || ! fClass->Property() ) {
   // fundamental types have no class, and unknown classes have no property
      std::string name = fName;

      if ( ! ( mod & Rflx::QUALIFIED ) )
         name = TClassEdit::CleanType( fName.c_str(), 1 );

      if ( mod & Rflx::FINAL )
         name = Utility::ResolveTypedef( name );

      return name;
   }

   if ( mod & Rflx::FINAL ) {
   /* The following G__ClassInfo lookup is badly broken ...
      G__ClassInfo* clInfo = (G__ClassInfo*)fClass->GetClassInfo();
      if ( mod & Rflx::SCOPED )
         return (clInfo && clInfo->Fullname()) ? clInfo->Fullname() : fClass->GetName();

   // unscoped name ...
      std::string actual = (clInfo && clInfo->Name()) ? clInfo->Name() : fClass->GetName();

   // in case of missing dictionaries, the scope won't have been stripped
      if ( ! ( clInfo && clInfo->IsValid() ) ) {
         std::string::size_type pos = actual.substr( 0, actual.find( '<' ) ).rfind( "::" );
         if ( pos != std::string::npos ) {
         // this is somewhat of a gamble, but the alternative is a guaranteed crash
            actual = actual.substr( pos + 2, std::string::npos );
         }
      }

      return actual;
   */
      return fClass->GetName();

   } else if ( ! ( mod & Rflx::SCOPED ) ) {
   /* The following G__ClassInfo lookup is badly broken ...
      G__ClassInfo* clInfo = (G__ClassInfo*)fClass->GetClassInfo();
      return (clInfo && clInfo->Name()) ? clInfo->Name() : fClass->GetName();
   */
      return fClass->GetName();
   }

   return fClass->GetName();
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::BaseSize() const
{
// get the total number of base classes that this class has
   if ( fClass.GetClass() && fClass->GetListOfBases() != 0 )
      return fClass->GetListOfBases()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TBaseAdapter PyROOT::TScopeAdapter::BaseAt( size_t nth ) const
{
// get the nth base of this class
   return (TBaseClass*)fClass->GetListOfBases()->At( nth );
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::FunctionMemberSize() const
{
// get the total number of methods that this class has
   if ( fClass.GetClass() )
      return fClass->GetListOfMethods()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TScopeAdapter::FunctionMemberAt( size_t nth ) const
{
// get the nth method of this class
   return (TMethod*)fClass->GetListOfMethods()->At( nth );
}

//____________________________________________________________________________
size_t PyROOT::TScopeAdapter::DataMemberSize() const
{
// get the total number of data members that this class has
   if ( fClass.GetClass() )
      return fClass->GetListOfDataMembers()->GetSize();

   return 0;
}

//____________________________________________________________________________
PyROOT::TMemberAdapter PyROOT::TScopeAdapter::DataMemberAt( size_t nth ) const
{
// get the nth data member of this class
   return (TDataMember*)fClass->GetListOfDataMembers()->At( nth );
}

//____________________________________________________________________________
PyROOT::TScopeAdapter::operator Bool_t() const
{
// check the validity of this scope (class)
   if ( fName.empty() )
      return false;

   Bool_t b = kFALSE;

   Int_t oldEIL = gErrorIgnoreLevel;
   gErrorIgnoreLevel = 3000;
   TClass* klass = TClass::GetClass( Name( Rflx::QUALIFIED | Rflx::SCOPED ).c_str() );
   if ( klass ) b = gInterpreter->ClassInfo_IsValid( klass->GetClassInfo() );
   gErrorIgnoreLevel = oldEIL;
   return b;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsComplete() const
{
// verify whether the dictionary of this class is fully available
   Bool_t b = kFALSE;

   TClass* klass = TClass::GetClass( Name( Rflx::SCOPED ).c_str() );
   if ( klass ) b = gInterpreter->ClassInfo_IsLoaded( klass->GetClassInfo() );
   return b;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsClass() const
{
// test if this scope represents a class
   if ( fClass.GetClass() ) {
   // some inverted logic: we don't have a TClass, but a builtin will be recognized, so
   // if it is NOT a builtin, it is a class or struct (but may be missing dictionary)
      return (fClass->Property() & kIsClass) || ! (fClass->Property() & kIsFundamental);
   }

// no class can mean either is no class (i.e. builtin), or no dict but coming in
// through PyCintex/Reflex ... as a workaround, use TDataTypes that has a full
// enumeration of builtin types
   return TDataType( Name( Rflx::FINAL | Rflx::SCOPED ).c_str() ).GetType() == kOther_t;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsStruct() const
{
// test if this scope represents a struct
   if ( fClass.GetClass() ) {
   // same logic as for IsClass() above ...
      return (fClass->Property() & kIsStruct) || ! (fClass->Property() & kIsFundamental);
   }

// same logic as for IsClass() above ...
   return TDataType( Name( Rflx::FINAL | Rflx::SCOPED ).c_str() ).GetType() == kOther_t;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsNamespace() const
{
// test if this scope represents a namespace
   if ( fClass.GetClass() )
      return fClass->Property() & G__BIT_ISNAMESPACE;

   return kFALSE;
}

//____________________________________________________________________________
Bool_t PyROOT::TScopeAdapter::IsAbstract() const
{
// test if this scope represents an abstract class
   if ( fClass.GetClass() )
      return fClass->Property() & kIsAbstract;   // assume set only for classes

   return kFALSE;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 Nagisa Sekiguchi
 *
 * 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 MISC_LIB_DETECT_HPP
#define MISC_LIB_DETECT_HPP

#include <type_traits>

#include "noncopyable.h"

BEGIN_MISC_LIB_NAMESPACE_DECL

template <bool B>
using enable_when = std::enable_if_t<B, std::nullptr_t>;

namespace __detail {

template <typename... T>
struct VoidHolder {
  using type = void;
};

} // namespace __detail

template <typename... T>
using void_t = typename __detail::VoidHolder<T...>::type;

namespace __detail {

struct NotDetected {
  NotDetected() = delete;
  ~NotDetected() = delete;
  NON_COPYABLE(NotDetected);
};

template <typename, template <typename...> class, typename...>
struct detector : std::false_type {
  using type = NotDetected;
};

template <template <typename...> class OP, typename... Arg>
struct detector<void_t<OP<Arg...>>, OP, Arg...> : std::true_type {
  using type = OP<Arg...>;
};

} // namespace __detail

template <template <typename...> class OP, typename... Arg>
constexpr auto is_detected_v = __detail::detector<void, OP, Arg...>::value;

template <template <typename...> class OP, typename... Arg>
using detected_t = typename __detail::detector<void, OP, Arg...>::type;

END_MISC_LIB_NAMESPACE_DECL

#endif // MISC_LIB_DETECT_HPP
<commit_msg>remove old code<commit_after>/*
 * Copyright (C) 2019 Nagisa Sekiguchi
 *
 * 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 MISC_LIB_DETECT_HPP
#define MISC_LIB_DETECT_HPP

#include <type_traits>

#include "noncopyable.h"

BEGIN_MISC_LIB_NAMESPACE_DECL

template <bool B>
using enable_when = std::enable_if_t<B, std::nullptr_t>;

namespace __detail {

struct NotDetected {
  NotDetected() = delete;
  ~NotDetected() = delete;
  NON_COPYABLE(NotDetected);
};

template <typename, template <typename...> class, typename...>
struct detector : std::false_type {
  using type = NotDetected;
};

template <template <typename...> class OP, typename... Arg>
struct detector<std::void_t<OP<Arg...>>, OP, Arg...> : std::true_type {
  using type = OP<Arg...>;
};

} // namespace __detail

template <template <typename...> class OP, typename... Arg>
constexpr auto is_detected_v = __detail::detector<void, OP, Arg...>::value;

template <template <typename...> class OP, typename... Arg>
using detected_t = typename __detail::detector<void, OP, Arg...>::type;

END_MISC_LIB_NAMESPACE_DECL

#endif // MISC_LIB_DETECT_HPP
<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "session_connection.h"

#include "flutter/fml/make_copyable.h"
#include "flutter/fml/trace_event.h"

#include "vsync_recorder.h"
#include "vsync_waiter.h"

namespace flutter_runner {

SessionConnection::SessionConnection(
    std::string debug_label,
    fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
    fml::closure session_error_callback,
    on_frame_presented_event on_frame_presented_callback,
    zx_handle_t vsync_event_handle,
    uint64_t max_frames_in_flight)
    : session_wrapper_(session.Bind(), nullptr),
      on_frame_presented_callback_(std::move(on_frame_presented_callback)),
      vsync_event_handle_(vsync_event_handle),
      kMaxFramesInFlight(max_frames_in_flight) {
  session_wrapper_.set_error_handler(
      [callback = session_error_callback](zx_status_t status) { callback(); });

  // Set the |fuchsia::ui::scenic::OnFramePresented()| event handler that will
  // fire every time a set of one or more frames is presented.
  session_wrapper_.set_on_frame_presented_handler(
      [this, handle = vsync_event_handle_](
          fuchsia::scenic::scheduling::FramePresentedInfo info) {
        // Update Scenic's limit for our remaining frames in flight allowed.
        size_t num_presents_handled = info.presentation_infos.size();
        frames_in_flight_allowed_ = info.num_presents_allowed;

        // A frame was presented: Update our |frames_in_flight| to match the
        // updated unfinalized present requests.
        frames_in_flight_ -= num_presents_handled;
        TRACE_EVENT2("gfx", "OnFramePresentedFelipe", "frames_in_flight",
                     frames_in_flight_, "max_frames_in_flight",
                     kMaxFramesInFlight);
        FML_DCHECK(frames_in_flight_ >= 0);

        VsyncRecorder::GetInstance().UpdateFramePresentedInfo(
            zx::time(info.actual_presentation_time));

        // Call the client-provided callback once we are done using |info|.
        on_frame_presented_callback_(std::move(info));

        if (present_session_pending_) {
          PresentSession();
        }
        ToggleSignal(handle, true);
      }  // callback
  );

  session_wrapper_.SetDebugName(debug_label);

  // Get information to finish initialization and only then allow Present()s.
  session_wrapper_.RequestPresentationTimes(
      /*requested_prediction_span=*/0,
      [this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
        frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;

        // If Scenic alloted us 0 frames to begin with, we should fail here.
        FML_CHECK(frames_in_flight_allowed_ > 0);

        VsyncRecorder::GetInstance().UpdateNextPresentationInfo(
            std::move(info));

        // Signal is initially high indicating availability of the session.
        ToggleSignal(vsync_event_handle_, true);
        initialized_ = true;

        PresentSession();
      });
}

SessionConnection::~SessionConnection() = default;

void SessionConnection::Present() {
  TRACE_EVENT2("gfx", "SessionConnection::Present", "frames_in_flight",
               frames_in_flight_, "max_frames_in_flight", kMaxFramesInFlight);

  TRACE_FLOW_BEGIN("gfx", "SessionConnection::PresentSession",
                   next_present_session_trace_id_);
  next_present_session_trace_id_++;

  present_requested_time_ = fml::TimePoint::Now();

  // Throttle frame submission to Scenic if we already have the maximum amount
  // of frames in flight. This allows the paint tasks for this frame to execute
  // in parallel with the presentation of previous frame but still provides
  // back-pressure to prevent us from enqueuing even more work.
  if (initialized_ && frames_in_flight_ < kMaxFramesInFlight) {
    PresentSession();
  } else {
    // We should never exceed the max frames in flight.
    FML_CHECK(frames_in_flight_ <= kMaxFramesInFlight);

    present_session_pending_ = true;
    ToggleSignal(vsync_event_handle_, false);
  }
}

fml::TimePoint SessionConnection::CalculateNextLatchPoint(
    fml::TimePoint present_requested_time,
    fml::TimePoint now,
    fml::TimePoint last_latch_point_targeted,
    fml::TimeDelta flutter_frame_build_time,
    fml::TimeDelta vsync_interval,
    std::deque<std::pair<fml::TimePoint, fml::TimePoint>>&
        future_presentation_infos) {
  // The minimum latch point is the largest of:
  // Now
  // When we expect the Flutter work for the frame to be completed
  // The last latch point targeted
  fml::TimePoint minimum_latch_point_to_target =
      std::max(std::max(now, present_requested_time + flutter_frame_build_time),
               last_latch_point_targeted);

  for (auto& info : future_presentation_infos) {
    fml::TimePoint latch_point = info.first;

    if (latch_point >= minimum_latch_point_to_target) {
      return latch_point;
    }
  }

  // We could not find a suitable latch point in the list given to us from
  // Scenic, so aim for the smallest safe value.
  return minimum_latch_point_to_target;
}

void SessionConnection::PresentSession() {
  TRACE_EVENT0("gfx", "SessionConnection::PresentSession");

  // If we cannot call Present2() because we have no more Scenic frame budget,
  // then we must wait until the OnFramePresented() event fires so we can
  // continue our work.
  if (frames_in_flight_allowed_ == 0) {
    FML_CHECK(!initialized_ || present_session_pending_);
    return;
  }

  present_session_pending_ = false;

  while (processed_present_session_trace_id_ < next_present_session_trace_id_) {
    TRACE_FLOW_END("gfx", "SessionConnection::PresentSession",
                   processed_present_session_trace_id_);
    processed_present_session_trace_id_++;
  }
  TRACE_FLOW_BEGIN("gfx", "Session::Present", next_present_trace_id_);
  next_present_trace_id_++;

  ++frames_in_flight_;

  // Flush all session ops. Paint tasks may not yet have executed but those are
  // fenced. The compositor can start processing ops while we finalize paint
  // tasks.

  fml::TimeDelta presentation_interval =
      VsyncRecorder::GetInstance().GetCurrentVsyncInfo().presentation_interval;

  fml::TimePoint next_latch_point = CalculateNextLatchPoint(
      fml::TimePoint::Now(), present_requested_time_,
      last_latch_point_targeted_,
      fml::TimeDelta::FromMicroseconds(0),  // flutter_frame_build_time
      presentation_interval, future_presentation_infos_);

  last_latch_point_targeted_ = next_latch_point;

  session_wrapper_.Present2(
      /*requested_presentation_time=*/next_latch_point.ToEpochDelta()
          .ToNanoseconds(),
      /*requested_prediction_span=*/presentation_interval.ToNanoseconds() * 10,
      [this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
        // Clear |future_presentation_infos_| and replace it with the updated
        // information.
        std::deque<std::pair<fml::TimePoint, fml::TimePoint>>().swap(
            future_presentation_infos_);

        for (fuchsia::scenic::scheduling::PresentationInfo& presentation_info :
             info.future_presentations) {
          future_presentation_infos_.push_back(
              {fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds(
                   presentation_info.latch_point())),
               fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds(
                   presentation_info.presentation_time()))});
        }

        frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;
        VsyncRecorder::GetInstance().UpdateNextPresentationInfo(
            std::move(info));
      });
}

void SessionConnection::ToggleSignal(zx_handle_t handle, bool set) {
  const auto signal = VsyncWaiter::SessionPresentSignal;
  auto status = zx_object_signal(handle,            // handle
                                 set ? 0 : signal,  // clear mask
                                 set ? signal : 0   // set mask
  );
  if (status != ZX_OK) {
    FML_LOG(ERROR) << "Could not toggle vsync signal: " << set;
  }
}

}  // namespace flutter_runner
<commit_msg>[fuchsia] fix typo (#21488)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "session_connection.h"

#include "flutter/fml/make_copyable.h"
#include "flutter/fml/trace_event.h"

#include "vsync_recorder.h"
#include "vsync_waiter.h"

namespace flutter_runner {

SessionConnection::SessionConnection(
    std::string debug_label,
    fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
    fml::closure session_error_callback,
    on_frame_presented_event on_frame_presented_callback,
    zx_handle_t vsync_event_handle,
    uint64_t max_frames_in_flight)
    : session_wrapper_(session.Bind(), nullptr),
      on_frame_presented_callback_(std::move(on_frame_presented_callback)),
      vsync_event_handle_(vsync_event_handle),
      kMaxFramesInFlight(max_frames_in_flight) {
  session_wrapper_.set_error_handler(
      [callback = session_error_callback](zx_status_t status) { callback(); });

  // Set the |fuchsia::ui::scenic::OnFramePresented()| event handler that will
  // fire every time a set of one or more frames is presented.
  session_wrapper_.set_on_frame_presented_handler(
      [this, handle = vsync_event_handle_](
          fuchsia::scenic::scheduling::FramePresentedInfo info) {
        // Update Scenic's limit for our remaining frames in flight allowed.
        size_t num_presents_handled = info.presentation_infos.size();
        frames_in_flight_allowed_ = info.num_presents_allowed;

        // A frame was presented: Update our |frames_in_flight| to match the
        // updated unfinalized present requests.
        frames_in_flight_ -= num_presents_handled;
        TRACE_EVENT2("gfx", "OnFramePresented", "frames_in_flight",
                     frames_in_flight_, "max_frames_in_flight",
                     kMaxFramesInFlight);
        FML_DCHECK(frames_in_flight_ >= 0);

        VsyncRecorder::GetInstance().UpdateFramePresentedInfo(
            zx::time(info.actual_presentation_time));

        // Call the client-provided callback once we are done using |info|.
        on_frame_presented_callback_(std::move(info));

        if (present_session_pending_) {
          PresentSession();
        }
        ToggleSignal(handle, true);
      }  // callback
  );

  session_wrapper_.SetDebugName(debug_label);

  // Get information to finish initialization and only then allow Present()s.
  session_wrapper_.RequestPresentationTimes(
      /*requested_prediction_span=*/0,
      [this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
        frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;

        // If Scenic alloted us 0 frames to begin with, we should fail here.
        FML_CHECK(frames_in_flight_allowed_ > 0);

        VsyncRecorder::GetInstance().UpdateNextPresentationInfo(
            std::move(info));

        // Signal is initially high indicating availability of the session.
        ToggleSignal(vsync_event_handle_, true);
        initialized_ = true;

        PresentSession();
      });
}

SessionConnection::~SessionConnection() = default;

void SessionConnection::Present() {
  TRACE_EVENT2("gfx", "SessionConnection::Present", "frames_in_flight",
               frames_in_flight_, "max_frames_in_flight", kMaxFramesInFlight);

  TRACE_FLOW_BEGIN("gfx", "SessionConnection::PresentSession",
                   next_present_session_trace_id_);
  next_present_session_trace_id_++;

  present_requested_time_ = fml::TimePoint::Now();

  // Throttle frame submission to Scenic if we already have the maximum amount
  // of frames in flight. This allows the paint tasks for this frame to execute
  // in parallel with the presentation of previous frame but still provides
  // back-pressure to prevent us from enqueuing even more work.
  if (initialized_ && frames_in_flight_ < kMaxFramesInFlight) {
    PresentSession();
  } else {
    // We should never exceed the max frames in flight.
    FML_CHECK(frames_in_flight_ <= kMaxFramesInFlight);

    present_session_pending_ = true;
    ToggleSignal(vsync_event_handle_, false);
  }
}

fml::TimePoint SessionConnection::CalculateNextLatchPoint(
    fml::TimePoint present_requested_time,
    fml::TimePoint now,
    fml::TimePoint last_latch_point_targeted,
    fml::TimeDelta flutter_frame_build_time,
    fml::TimeDelta vsync_interval,
    std::deque<std::pair<fml::TimePoint, fml::TimePoint>>&
        future_presentation_infos) {
  // The minimum latch point is the largest of:
  // Now
  // When we expect the Flutter work for the frame to be completed
  // The last latch point targeted
  fml::TimePoint minimum_latch_point_to_target =
      std::max(std::max(now, present_requested_time + flutter_frame_build_time),
               last_latch_point_targeted);

  for (auto& info : future_presentation_infos) {
    fml::TimePoint latch_point = info.first;

    if (latch_point >= minimum_latch_point_to_target) {
      return latch_point;
    }
  }

  // We could not find a suitable latch point in the list given to us from
  // Scenic, so aim for the smallest safe value.
  return minimum_latch_point_to_target;
}

void SessionConnection::PresentSession() {
  TRACE_EVENT0("gfx", "SessionConnection::PresentSession");

  // If we cannot call Present2() because we have no more Scenic frame budget,
  // then we must wait until the OnFramePresented() event fires so we can
  // continue our work.
  if (frames_in_flight_allowed_ == 0) {
    FML_CHECK(!initialized_ || present_session_pending_);
    return;
  }

  present_session_pending_ = false;

  while (processed_present_session_trace_id_ < next_present_session_trace_id_) {
    TRACE_FLOW_END("gfx", "SessionConnection::PresentSession",
                   processed_present_session_trace_id_);
    processed_present_session_trace_id_++;
  }
  TRACE_FLOW_BEGIN("gfx", "Session::Present", next_present_trace_id_);
  next_present_trace_id_++;

  ++frames_in_flight_;

  // Flush all session ops. Paint tasks may not yet have executed but those are
  // fenced. The compositor can start processing ops while we finalize paint
  // tasks.

  fml::TimeDelta presentation_interval =
      VsyncRecorder::GetInstance().GetCurrentVsyncInfo().presentation_interval;

  fml::TimePoint next_latch_point = CalculateNextLatchPoint(
      fml::TimePoint::Now(), present_requested_time_,
      last_latch_point_targeted_,
      fml::TimeDelta::FromMicroseconds(0),  // flutter_frame_build_time
      presentation_interval, future_presentation_infos_);

  last_latch_point_targeted_ = next_latch_point;

  session_wrapper_.Present2(
      /*requested_presentation_time=*/next_latch_point.ToEpochDelta()
          .ToNanoseconds(),
      /*requested_prediction_span=*/presentation_interval.ToNanoseconds() * 10,
      [this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
        // Clear |future_presentation_infos_| and replace it with the updated
        // information.
        std::deque<std::pair<fml::TimePoint, fml::TimePoint>>().swap(
            future_presentation_infos_);

        for (fuchsia::scenic::scheduling::PresentationInfo& presentation_info :
             info.future_presentations) {
          future_presentation_infos_.push_back(
              {fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds(
                   presentation_info.latch_point())),
               fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds(
                   presentation_info.presentation_time()))});
        }

        frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;
        VsyncRecorder::GetInstance().UpdateNextPresentationInfo(
            std::move(info));
      });
}

void SessionConnection::ToggleSignal(zx_handle_t handle, bool set) {
  const auto signal = VsyncWaiter::SessionPresentSignal;
  auto status = zx_object_signal(handle,            // handle
                                 set ? 0 : signal,  // clear mask
                                 set ? signal : 0   // set mask
  );
  if (status != ZX_OK) {
    FML_LOG(ERROR) << "Could not toggle vsync signal: " << set;
  }
}

}  // namespace flutter_runner
<|endoftext|>


<commit_before>//
// Copyright (C) 2007-2010 SIPez LLC.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Keith Kyzivat <kkyzivat AT SIPez DOT com>

#include <os/OsIntTypes.h>
#include <sipxunittests.h>
#include <mp/MpBufPool.h>
#include <mp/MpArrayBuf.h>
#include <mp/MpAudioBuf.h>
#include <mp/MpInputDeviceManager.h>
#ifdef WIN32
#include <mp/MpidWinMM.h>
#elif defined ANDROID
#include <mp/MpidAndroid.h>
#elif defined __linux__
#include <mp/MpidOss.h>
#elif defined __APPLE__
#include <mp/MpidCoreAudio.h>
#else
#include <mp/MpSineWaveGeneratorDeviceDriver.h>
#endif
#include <os/OsTask.h>
#include <utl/UtlString.h>

#define MIDDT_SAMPLES_PER_FRAME 80
#define MIDDT_NBUFS 20

class MpInputDeviceDriverTest : public SIPX_UNIT_BASE_CLASS
{
   CPPUNIT_TEST_SUITE(MpInputDeviceDriverTest);
   CPPUNIT_TEST(testSetup);
   CPPUNIT_TEST_SUITE_END();

private:
   MpBufPool* mpBufPool;
   MpBufPool* mpHeadersPool;

   int mNumBufferedFrames;
   unsigned int mSamplesPerSecond;
   unsigned int mFramePeriodMSecs;

public:
   void setUp()
   {
      mpBufPool =
         new MpBufPool(MIDDT_SAMPLES_PER_FRAME * sizeof(MpAudioSample)
                       + MpArrayBuf::getHeaderSize(),
                       MIDDT_NBUFS);
      CPPUNIT_ASSERT(mpBufPool != NULL);

      // Create pool for buffer headers
      mpHeadersPool = new MpBufPool(sizeof(MpAudioBuf), MIDDT_NBUFS);
      CPPUNIT_ASSERT(mpHeadersPool != NULL);

      // Set mpHeadersPool as default pool for audio and data pools.
      MpAudioBuf::smpDefaultPool = mpHeadersPool;
      MpDataBuf::smpDefaultPool = mpHeadersPool;

      mNumBufferedFrames = 5;
      mSamplesPerSecond = 8000;
      mFramePeriodMSecs = MIDDT_SAMPLES_PER_FRAME * 1000 / mSamplesPerSecond;
   }

   void testSetup()
   {
      MpInputDeviceManager inDevMgr(MIDDT_SAMPLES_PER_FRAME,
                                    mSamplesPerSecond,
                                    mNumBufferedFrames,
                                    *mpBufPool);

      // Buffer for recorded data.
      MpAudioSample* pRecordBuffer = new MpAudioSample[mNumBufferedFrames* MIDDT_SAMPLES_PER_FRAME];
      int pRecordBufferPointer = 0;

      MpInputDeviceDriver* pInDevDriver =
#ifdef WIN32
         new MpidWinMM(MpidWinMM::getDefaultDeviceName(), inDevMgr);
#elif defined ANDROID
         new MpidAndroid(MpidAndroid::AUDIO_SOURCE_DEFAULT, inDevMgr);
#elif defined __linux__
         new MpidOss("/dev/dsp", inDevMgr);
#elif defined __APPLE__
         new MpidCoreAudio("[default]", inDevMgr);
#else
         new MpSineWaveGeneratorDeviceDriver("SineWaveDriver", inDevMgr,
                                             3000, 3000, 0);
#endif
      if (pInDevDriver != NULL)
      {
         // Verify that our device is indeed valid and, if not using the test
         // driver, is indeed pointing at an actual device in the OS.
         CPPUNIT_ASSERT(pInDevDriver->isDeviceValid());

         // Since we've only just created this device, it shouldn't be enabled.
         CPPUNIT_ASSERT(!pInDevDriver->isEnabled());
         // And shouldn't have a valid device handle/ID.
         CPPUNIT_ASSERT(pInDevDriver->getDeviceId() < 0);

         // Try to enable the device when it isn't added to a manager..
         // SHOULDN'T DO THIS - Only the manager should be able to do this..
         // perhaps enabling should be protected, and manager be friended?
         //CPPUNIT_ASSERT(iDrv->enableDevice(10,10,10) != OS_SUCCESS);

         // Add the device to an input manager.
         MpInputDeviceHandle iDrvHnd = inDevMgr.addDevice(*pInDevDriver);

         // Verify it has a valid handle/ID.
         CPPUNIT_ASSERT(iDrvHnd > 0);

         // Try to disable it -- this should fail, since it isn't enabled yet.
         // Also note that one should be disabling/enabling via the manager..
         // I'm just verifying that disabling the device itself when it isn't
         // set up doesn't kill things.
         CPPUNIT_ASSERT(pInDevDriver->disableDevice() != OS_SUCCESS);

         // Now enable it via the manager -- this should succeed.
         CPPUNIT_ASSERT(inDevMgr.enableDevice(iDrvHnd) == OS_SUCCESS);

         int nMSPerBuffer = mNumBufferedFrames * mFramePeriodMSecs;
         unsigned nMSecsToRecord = 5000;
         double* derivs = new double[(mNumBufferedFrames-1)*(nMSecsToRecord/nMSPerBuffer)];
         // Round nMSecsToRecord to nMSPerBuffer boundary.
         nMSecsToRecord = (nMSecsToRecord/nMSPerBuffer) * nMSPerBuffer;

         UtlString derivPlotStr;
         derivPlotStr.capacity((nMSecsToRecord/mFramePeriodMSecs) << 2);
         UtlString derivWAvgStr;

         unsigned i;
         for(i=0;i<(mNumBufferedFrames-1)*(nMSecsToRecord/nMSPerBuffer);i++)
            derivs[i] = -1;

         unsigned derivBufPos;
         unsigned derivBufSz = 0;
         unsigned nDerivsPerBuf = mNumBufferedFrames-1;
         for(i = 0, derivBufPos = 0;
             i < nMSecsToRecord;
             i = i+nMSPerBuffer, derivBufPos += nDerivsPerBuf)
         {
            // Reset nDerivsPerBuf, as getting time derivs could have changed it.
            nDerivsPerBuf = mNumBufferedFrames-1;

            // Sleep till when the input buffer should be full
            OsTask::delay(nMSPerBuffer);

            // Grab time derivative statistics..
            double* curDerivFramePtr = (double*)(derivs + derivBufPos);
            CPPUNIT_ASSERT_EQUAL(OS_SUCCESS,
                                 inDevMgr.getTimeDerivatives(iDrvHnd,
                                                             nDerivsPerBuf,
                                                             curDerivFramePtr));
            derivBufSz += nDerivsPerBuf;
         }

         // Ok, now disable it via the manager -- this time it should succeed.
         CPPUNIT_ASSERT(inDevMgr.disableDevice(iDrvHnd) == OS_SUCCESS);

         // Define weighted average accumulator and period.
         double derivWeightedAverage = 0;
         int derivWAvgPeriod = 5;

         // Now that we have all the derivatives,
         // make a string out of em..
         for(i = 0; i < derivBufSz; i++)
         {
            // Prepare the derivative line to print.
#           define NUMSTRSZ 32
            char tmpBuf[NUMSTRSZ];

            // Add derivative to our big-long string that can be used for plotting.
            snprintf(tmpBuf, NUMSTRSZ, "%.2f", derivs[i]);
            derivPlotStr.append(tmpBuf);
            if(i < derivBufSz-1) // While there's still one more, put a comma
               derivPlotStr.append(", ");

            if ((i != 0) && (i % derivWAvgPeriod) == 0)
            {
               // Now that we have derivWAvgPeriod samples,
               // calculate and assign the actual weighted average.
               derivWeightedAverage = derivWeightedAverage / derivWAvgPeriod;

               // Now append this to our weighted average string.
               snprintf(tmpBuf, NUMSTRSZ, "%.2f", derivWeightedAverage);
               derivWAvgStr.append(tmpBuf);
               derivWAvgStr.append(", ");

               // reset the weighted average collector.
               derivWeightedAverage = 0;
            }

            derivWeightedAverage += derivs[i];

            CPPUNIT_ASSERT(derivs[i] <= 4);
         }

         // Remove the device from the manager explicitly,
         // Otherwise the manager will assert fail if there are devices
         // still present when the manager is destroyed
         inDevMgr.removeDevice(iDrvHnd);

         // Now print out our derivative results.
         printf(" derivatives: %s\n", derivPlotStr.data());
         printf("weighted avg: %s\n", derivWAvgStr.data());
      }  // if pInDevDriver != NULL
   }

   void tearDown()
   {
      if (mpBufPool != NULL)
      {
         delete mpBufPool;
      }
      if (mpHeadersPool != NULL)
      {
         delete mpHeadersPool;
      }
   }
};

CPPUNIT_TEST_SUITE_REGISTRATION(MpInputDeviceDriverTest);

<commit_msg>Android device dreiver initialization for InputDeviceDriver unit test<commit_after>//
// Copyright (C) 2007-2010 SIPez LLC.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Keith Kyzivat <kkyzivat AT SIPez DOT com>

#include <os/OsIntTypes.h>
#include <sipxunittests.h>
#include <mp/MpBufPool.h>
#include <mp/MpArrayBuf.h>
#include <mp/MpAudioBuf.h>
#include <mp/MpInputDeviceManager.h>
#ifdef WIN32
#include <mp/MpidWinMM.h>
#elif defined ANDROID
#   include <mp/MpidAndroid.h>
#   include <mp/MpAndroidAudioTrack.h>
#elif defined __linux__
#include <mp/MpidOss.h>
#elif defined __APPLE__
#include <mp/MpidCoreAudio.h>
#else
#include <mp/MpSineWaveGeneratorDeviceDriver.h>
#endif
#include <os/OsTask.h>
#include <utl/UtlString.h>

#define MIDDT_SAMPLES_PER_FRAME 80
#define MIDDT_NBUFS 20

class MpInputDeviceDriverTest : public SIPX_UNIT_BASE_CLASS
{
   CPPUNIT_TEST_SUITE(MpInputDeviceDriverTest);
   CPPUNIT_TEST(testSetup);
   CPPUNIT_TEST_SUITE_END();

private:
   MpBufPool* mpBufPool;
   MpBufPool* mpHeadersPool;

   int mNumBufferedFrames;
   unsigned int mSamplesPerSecond;
   unsigned int mFramePeriodMSecs;

public:
   void setUp()
   {
#ifdef ANDROID
      OsStatus stat = MpAndroidAudioTrack::setAudioTrackCreator();
#endif

      mpBufPool =
         new MpBufPool(MIDDT_SAMPLES_PER_FRAME * sizeof(MpAudioSample)
                       + MpArrayBuf::getHeaderSize(),
                       MIDDT_NBUFS);
      CPPUNIT_ASSERT(mpBufPool != NULL);

      // Create pool for buffer headers
      mpHeadersPool = new MpBufPool(sizeof(MpAudioBuf), MIDDT_NBUFS);
      CPPUNIT_ASSERT(mpHeadersPool != NULL);

      // Set mpHeadersPool as default pool for audio and data pools.
      MpAudioBuf::smpDefaultPool = mpHeadersPool;
      MpDataBuf::smpDefaultPool = mpHeadersPool;

      mNumBufferedFrames = 5;
      mSamplesPerSecond = 8000;
      mFramePeriodMSecs = MIDDT_SAMPLES_PER_FRAME * 1000 / mSamplesPerSecond;
   }

   void testSetup()
   {
      MpInputDeviceManager inDevMgr(MIDDT_SAMPLES_PER_FRAME,
                                    mSamplesPerSecond,
                                    mNumBufferedFrames,
                                    *mpBufPool);

      // Buffer for recorded data.
      MpAudioSample* pRecordBuffer = new MpAudioSample[mNumBufferedFrames* MIDDT_SAMPLES_PER_FRAME];
      int pRecordBufferPointer = 0;

      MpInputDeviceDriver* pInDevDriver =
#ifdef WIN32
         new MpidWinMM(MpidWinMM::getDefaultDeviceName(), inDevMgr);
#elif defined ANDROID
         new MpidAndroid(MpidAndroid::AUDIO_SOURCE_DEFAULT, inDevMgr);
#elif defined __linux__
         new MpidOss("/dev/dsp", inDevMgr);
#elif defined __APPLE__
         new MpidCoreAudio("[default]", inDevMgr);
#else
         new MpSineWaveGeneratorDeviceDriver("SineWaveDriver", inDevMgr,
                                             3000, 3000, 0);
#endif
      if (pInDevDriver != NULL)
      {
         // Verify that our device is indeed valid and, if not using the test
         // driver, is indeed pointing at an actual device in the OS.
         CPPUNIT_ASSERT(pInDevDriver->isDeviceValid());

         // Since we've only just created this device, it shouldn't be enabled.
         CPPUNIT_ASSERT(!pInDevDriver->isEnabled());
         // And shouldn't have a valid device handle/ID.
         CPPUNIT_ASSERT(pInDevDriver->getDeviceId() < 0);

         // Try to enable the device when it isn't added to a manager..
         // SHOULDN'T DO THIS - Only the manager should be able to do this..
         // perhaps enabling should be protected, and manager be friended?
         //CPPUNIT_ASSERT(iDrv->enableDevice(10,10,10) != OS_SUCCESS);

         // Add the device to an input manager.
         MpInputDeviceHandle iDrvHnd = inDevMgr.addDevice(*pInDevDriver);

         // Verify it has a valid handle/ID.
         CPPUNIT_ASSERT(iDrvHnd > 0);

         // Try to disable it -- this should fail, since it isn't enabled yet.
         // Also note that one should be disabling/enabling via the manager..
         // I'm just verifying that disabling the device itself when it isn't
         // set up doesn't kill things.
         CPPUNIT_ASSERT(pInDevDriver->disableDevice() != OS_SUCCESS);

         // Now enable it via the manager -- this should succeed.
         CPPUNIT_ASSERT(inDevMgr.enableDevice(iDrvHnd) == OS_SUCCESS);

         int nMSPerBuffer = mNumBufferedFrames * mFramePeriodMSecs;
         unsigned nMSecsToRecord = 5000;
         double* derivs = new double[(mNumBufferedFrames-1)*(nMSecsToRecord/nMSPerBuffer)];
         // Round nMSecsToRecord to nMSPerBuffer boundary.
         nMSecsToRecord = (nMSecsToRecord/nMSPerBuffer) * nMSPerBuffer;

         UtlString derivPlotStr;
         derivPlotStr.capacity((nMSecsToRecord/mFramePeriodMSecs) << 2);
         UtlString derivWAvgStr;

         unsigned i;
         for(i=0;i<(mNumBufferedFrames-1)*(nMSecsToRecord/nMSPerBuffer);i++)
            derivs[i] = -1;

         unsigned derivBufPos;
         unsigned derivBufSz = 0;
         unsigned nDerivsPerBuf = mNumBufferedFrames-1;
         for(i = 0, derivBufPos = 0;
             i < nMSecsToRecord;
             i = i+nMSPerBuffer, derivBufPos += nDerivsPerBuf)
         {
            // Reset nDerivsPerBuf, as getting time derivs could have changed it.
            nDerivsPerBuf = mNumBufferedFrames-1;

            // Sleep till when the input buffer should be full
            OsTask::delay(nMSPerBuffer);

            // Grab time derivative statistics..
            double* curDerivFramePtr = (double*)(derivs + derivBufPos);
            CPPUNIT_ASSERT_EQUAL(OS_SUCCESS,
                                 inDevMgr.getTimeDerivatives(iDrvHnd,
                                                             nDerivsPerBuf,
                                                             curDerivFramePtr));
            derivBufSz += nDerivsPerBuf;
         }

         // Ok, now disable it via the manager -- this time it should succeed.
         CPPUNIT_ASSERT(inDevMgr.disableDevice(iDrvHnd) == OS_SUCCESS);

         // Define weighted average accumulator and period.
         double derivWeightedAverage = 0;
         int derivWAvgPeriod = 5;

         // Now that we have all the derivatives,
         // make a string out of em..
         for(i = 0; i < derivBufSz; i++)
         {
            // Prepare the derivative line to print.
#           define NUMSTRSZ 32
            char tmpBuf[NUMSTRSZ];

            // Add derivative to our big-long string that can be used for plotting.
            snprintf(tmpBuf, NUMSTRSZ, "%.2f", derivs[i]);
            derivPlotStr.append(tmpBuf);
            if(i < derivBufSz-1) // While there's still one more, put a comma
               derivPlotStr.append(", ");

            if ((i != 0) && (i % derivWAvgPeriod) == 0)
            {
               // Now that we have derivWAvgPeriod samples,
               // calculate and assign the actual weighted average.
               derivWeightedAverage = derivWeightedAverage / derivWAvgPeriod;

               // Now append this to our weighted average string.
               snprintf(tmpBuf, NUMSTRSZ, "%.2f", derivWeightedAverage);
               derivWAvgStr.append(tmpBuf);
               derivWAvgStr.append(", ");

               // reset the weighted average collector.
               derivWeightedAverage = 0;
            }

            derivWeightedAverage += derivs[i];

            CPPUNIT_ASSERT(derivs[i] <= 4);
         }

         // Remove the device from the manager explicitly,
         // Otherwise the manager will assert fail if there are devices
         // still present when the manager is destroyed
         inDevMgr.removeDevice(iDrvHnd);

         // Now print out our derivative results.
         printf(" derivatives: %s\n", derivPlotStr.data());
         printf("weighted avg: %s\n", derivWAvgStr.data());
      }  // if pInDevDriver != NULL
   }

   void tearDown()
   {
      if (mpBufPool != NULL)
      {
         delete mpBufPool;
      }
      if (mpHeadersPool != NULL)
      {
         delete mpHeadersPool;
      }
   }
};

CPPUNIT_TEST_SUITE_REGISTRATION(MpInputDeviceDriverTest);

<|endoftext|>


<commit_before>#ifdef HX_LINUX

#include "snow_core.h"

#include <string>

#ifndef SNOW_NO_GTK
    #include <gtk/gtk.h>
#endif //SNOW_NO_GTK

namespace snow {

    namespace core {

        void init_platform() {

            #ifndef SNOW_NO_GTK
                gtk_init(NULL, NULL);
            #endif //SNOW_NO_GTK

        } //init_core_platform

        void shutdown_platform() {

        } //shutdown_core_platform

        void update_platform() {

        } //update_core_platform

        void on_system_event_platform( const SystemEventType event ) {

        } //on_system_event_platform

    } //core namespace

    namespace io {

        void url_open(const std::string &url) {

        } //url_open

    } //io namespace

} //snow namespace

#endif //HX_LINUX
<commit_msg>Initial linux url_open<commit_after>#ifdef HX_LINUX

#include "snow_core.h"

#include <string>

#ifndef SNOW_NO_GTK
    #include <gtk/gtk.h>
#endif //SNOW_NO_GTK

namespace snow {

    namespace core {

        void init_platform() {

            #ifndef SNOW_NO_GTK
                gtk_init(NULL, NULL);
            #endif //SNOW_NO_GTK

        } //init_core_platform

        void shutdown_platform() {

        } //shutdown_core_platform

        void update_platform() {

        } //update_core_platform

        void on_system_event_platform( const SystemEventType event ) {

        } //on_system_event_platform

    } //core namespace

    namespace io {

        void url_open(const std::string &url) {

            std::string cmd = "xdg-open " + url;
            popen(cmd.c_str(), "r")

        } //url_open

    } //io namespace

} //snow namespace

#endif //HX_LINUX
<|endoftext|>


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

#include <ResourceManager/LuaParser.hpp>

namespace rm
{

////////////////////////////////////////////////////////////
/// Initialise static members
////////////////////////////////////////////////////////////

lua_State* LuaParser::m_luaState = nullptr;

////////////////////////////////////////////////////////////
/// Function definitions
////////////////////////////////////////////////////////////

// Convert any type of Lua value at the given acceptable index to a string
static std::string stringify(lua_State* L, int index)
{
    // If the value is a string or a number, which is always convertible to a string
    if (lua_isstring(L, index))
    {
        return lua_tostring(L, index);
    }
    else
    {
        // Get the type of the value
        int type = lua_type(L, index);

        // If the type of value is a boolean, convert to its equivalent string representation
        if (type == LUA_TBOOLEAN)
        {
            return std::string(lua_toboolean(L, index) ? "true" : "false");
        }
        // Return the name of the type for any other type of value
        else
        {
            return std::string(lua_typename(L, type));
        }
    }
}

////////////////////////////////////////////////////////////
ResourceDataList LuaParser::parsePack(const std::string& path)
{
    // Create a resource data list to hold the data of every resource in every resource pack
    ResourceDataList resourceDataList;
    // Create a string vector to hold the path of every resource pack to be parsed
    std::vector<std::string> resourcePacks = {path};

    // Iterate through each resource pack until there are none remaining
    for (auto i = 0; i < resourcePacks.size(); i++)
    {
        // Get a list of every resource in the current resource pack
        ResourceDataList leaves = leafPack(resourcePacks[i]);

        // Iterate through each resource
        for (auto j = leaves.begin(); j != leaves.end(); j++)
        {
            // If the current resource is a resource pack
            if (j->isResourcePack)
            {
                // If the resource pack has already been parsed, ignore it and log a warning message
                if (std::find(resourcePacks.begin(), resourcePacks.end(), j->path) != resourcePacks.end())
                {
                    Logger::logMessage("Cyclic dependency detected in ", j->path);
                }
                // Otherwise, add it as a pending resource pack to be parsed
                else
                {
                    resourcePacks.push_back(j->path);
                }
            }
            // Otherwise, add it to the resource data list
            else
            {
                resourceDataList.push_back(*j);
            }
        }
    }

    // Return the resource data list
    return resourceDataList;
}

////////////////////////////////////////////////////////////
ResourceDataList LuaParser::leafPack(const std::string& path)
{
    // Create a resource data list to hold the data of each resource
    ResourceDataList resourceDataList;

    // Create a new Lua state
    m_luaState = luaL_newstate();
    // Open all standard Lua libraries into the given state
    luaL_openlibs(m_luaState);

    // Try to load and run the resource pack file
    if (luaL_dofile(m_luaState, path.data()) != 0)
    {
        // Log errors on failure
        Logger::logMessage("Resource pack parsing failed for ", path);
        Logger::logMessage(lua_tostring(m_luaState, -1));
    }
    // On success
    else
    {
        // Push a nil value onto the Lua stack
        lua_pushnil(m_luaState);

        // Iterate through each key on the Lua stack at the given index
        while (lua_next(m_luaState, -2) != 0)
        {
            // Push a nil value onto the Lua stack
            lua_pushnil(m_luaState);

            // Get the resource data
            auto leaf = parseLeaf();

            // If parsing succeeded
            if(leaf.isValid)
            {
                // Add it to the resource data list
                resourceDataList.push_back(leaf);
            }
            // Pop one element from the Lua stack
            lua_pop(m_luaState, 1);
        }

    }

    // Destroy all objects and free all dynamic memory used by the Lua state
    lua_close(m_luaState);

    // Reset the Lua state pointer
    m_luaState = nullptr;
    // Return the resource data list
    return resourceDataList;
}

////////////////////////////////////////////////////////////
ResourceData LuaParser::parseLeaf()
{
    // Create a resource data object to hold the leaf data
    ResourceData resourceData;

    // Ensure valid lua context
    if(!m_luaState)
    {
        Logger::logMessage("LuaParser tried to parse leaf with invalid lua context");
        resourceData.isValid = false;
        return resourceData;
    }

    // Valid until proven guilty
    resourceData.isValid = true;

    // Assume the leaf is not a resource pack
    resourceData.isResourcePack = false;

    // Iterate through each key on the Lua stack at the given index
    while (lua_next(m_luaState, -2) != 0)
    {
        // Get the key-value pair as strings
        std::string key   = stringify(m_luaState, -2);
        std::string value = stringify(m_luaState, -1);

        // If the value of the key represents a path
        if (key == "path")
        {
            resourceData.path = value;
        }
        // If the value of the key represents a type
        else if (key == "type")
        {
            // If the leaf is a resource pack
            if (value == "resourcepack")
            {
                resourceData.isResourcePack = true;
            }

            resourceData.type = value;
        }
        // If the value of the key represents an alias
        else if (key == "alias")
        {
            resourceData.alias = value;
        }

        // Pop one element from the Lua stack
        lua_pop(m_luaState, 1);
    }

    // If no path is present, return invalid
    if(resourceData.path.size() == 0)
    {
        Logger::logMessage("Resource missing path attribute: ", resourceData.alias, " ", resourceData.type);
        resourceData.isValid = false;
        return resourceData;
    }

    // If no path is present, return invalid
    if(resourceData.type.size() == 0)
    {
        Logger::logMessage("Resource missing type attribute: ", resourceData.alias, " ", resourceData.path);
        resourceData.isValid = false;
        return resourceData;
    }

    // If no alias is present, set it as it's path
    if(resourceData.alias.size() == 0)
    {
        resourceData.alias = resourceData.path;
    }

    // Return the resource data
    return resourceData;
}

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

#include <ResourceManager/LuaParser.hpp>

namespace rm
{

////////////////////////////////////////////////////////////
/// Initialise static members
////////////////////////////////////////////////////////////

lua_State* LuaParser::m_luaState = nullptr;

////////////////////////////////////////////////////////////
/// Function definitions
////////////////////////////////////////////////////////////

// Convert any type of Lua value at the given acceptable index to a string
static std::string stringify(lua_State* L, int index)
{
    // If the value is a string or a number, which is always convertible to a string
    if (lua_isstring(L, index))
    {
        return lua_tostring(L, index);
    }
    else
    {
        // Get the type of the value
        int type = lua_type(L, index);

        // If the type of value is a boolean, convert to its equivalent string representation
        if (type == LUA_TBOOLEAN)
        {
            return std::string(lua_toboolean(L, index) ? "true" : "false");
        }
        // Return the name of the type for any other type of value
        else
        {
            return std::string(lua_typename(L, type));
        }
    }
}

////////////////////////////////////////////////////////////
ResourceDataList LuaParser::parsePack(const std::string& path)
{
    // Create a resource data list to hold the data of every resource in every resource pack
    ResourceDataList resourceDataList;

    // Create a string vector to hold the path of every resource pack to be parsed
    std::vector<std::string> resourcePacks = {path};

    // Iterate through each resource pack until there are none remaining
    for (auto i = 0; i < resourcePacks.size(); i++)
    {
        // Get a list of every resource in the current resource pack
        ResourceDataList leaves = leafPack(resourcePacks[i]);

        // Iterate through each resource
        for (auto j = leaves.begin(); j != leaves.end(); j++)
        {
            // If the current resource is a resource pack
            if (j->isResourcePack)
            {
                // If the resource pack has already been parsed, ignore it and log a warning message
                if (std::find(resourcePacks.begin(), resourcePacks.end(), j->path) != resourcePacks.end())
                {
                    Logger::logMessage("Cyclic dependency detected in ", j->path);
                }
                // Otherwise, add it as a pending resource pack to be parsed
                else
                {
                    resourcePacks.push_back(j->path);
                }
            }
            // Otherwise, add it to the resource data list
            else
            {
                resourceDataList.push_back(*j);
            }
        }
    }

    // Return the resource data list
    return resourceDataList;
}

////////////////////////////////////////////////////////////
ResourceDataList LuaParser::leafPack(const std::string& path)
{
    // Create a resource data list to hold the data of each resource
    ResourceDataList resourceDataList;

    // Flag for if errors occured during parsing
    bool didErrorsOccur = false;

    // Create a new Lua state
    m_luaState = luaL_newstate();
    // Open all standard Lua libraries into the given state
    luaL_openlibs(m_luaState);

    // Try to load and run the resource pack file
    if (luaL_dofile(m_luaState, path.data()) != 0)
    {
        // Log errors on failure
        Logger::logMessage("Resource pack parsing failed for ", path);
        Logger::logMessage(lua_tostring(m_luaState, -1));
    }
    // On success
    else
    {
        // Push a nil value onto the Lua stack
        lua_pushnil(m_luaState);

        // Iterate through each key on the Lua stack at the given index
        while (lua_next(m_luaState, -2) != 0)
        {
            // Push a nil value onto the Lua stack
            lua_pushnil(m_luaState);

            // Get the resource data
            auto leaf = parseLeaf();

            // Set didErrorsOccur appropriately
            didErrorsOccur |= !leaf.isValid;

            // If parsing succeeded
            if(leaf.isValid)
            {
                // Add it to the resource data list
                resourceDataList.push_back(leaf);
            }
            // Pop one element from the Lua stack
            lua_pop(m_luaState, 1);
        }
    }

    if(didErrorsOccur)
    {
        Logger::logMessage("Errors occured while parsing leaves in ", path);
    }

    // Destroy all objects and free all dynamic memory used by the Lua state
    lua_close(m_luaState);

    // Reset the Lua state pointer
    m_luaState = nullptr;
    // Return the resource data list
    return resourceDataList;
}

////////////////////////////////////////////////////////////
ResourceData LuaParser::parseLeaf()
{
    // Create a resource data object to hold the leaf data
    ResourceData resourceData;

    // Ensure valid lua context
    if(!m_luaState)
    {
        Logger::logMessage("LuaParser tried to parse leaf with invalid lua context");
        resourceData.isValid = false;
        return resourceData;
    }

    // Valid until proven guilty
    resourceData.isValid = true;

    // Assume the leaf is not a resource pack
    resourceData.isResourcePack = false;

    // Iterate through each key on the Lua stack at the given index
    while (lua_next(m_luaState, -2) != 0)
    {
        // Get the key-value pair as strings
        std::string key   = stringify(m_luaState, -2);
        std::string value = stringify(m_luaState, -1);

        // If the value of the key represents a path
        if (key == "path")
        {
            resourceData.path = value;
        }
        // If the value of the key represents a type
        else if (key == "type")
        {
            // If the leaf is a resource pack
            if (value == "resourcepack")
            {
                resourceData.isResourcePack = true;
            }

            resourceData.type = value;
        }
        // If the value of the key represents an alias
        else if (key == "alias")
        {
            resourceData.alias = value;
        }

        // Pop one element from the Lua stack
        lua_pop(m_luaState, 1);
    }

    // If no path is present, return invalid
    if(resourceData.path.size() == 0)
    {
        Logger::logMessage("Resource missing path attribute: ", resourceData.alias, " ", resourceData.type);
        resourceData.isValid = false;
        return resourceData;
    }

    // If no path is present, return invalid
    if(resourceData.type.size() == 0)
    {
        Logger::logMessage("Resource missing type attribute: ", resourceData.alias, " ", resourceData.path);
        resourceData.isValid = false;
        return resourceData;
    }

    // If no alias is present, set it as it's path
    if(resourceData.alias.size() == 0)
    {
        resourceData.alias = resourceData.path;
    }

    // Return the resource data
    return resourceData;
}

} // rm
<|endoftext|>