<commit_before>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/mpi.h>
#include <deal.II/base/utilities.h>
#include <deal.II/base/exceptions.h>

#include <cstddef>
#include <iostream>

#ifdef DEAL_II_USE_TRILINOS
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <Epetra_MpiComm.h>
#    include <deal.II/lac/vector_memory.h>
#    include <deal.II/lac/trilinos_vector.h>
#    include <deal.II/lac/trilinos_block_vector.h>
#  endif
#endif

#ifdef DEAL_II_USE_PETSC
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <petscsys.h>
#  endif
#endif

DEAL_II_NAMESPACE_OPEN

namespace Utilities
{

  namespace MPI
  {
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
                                // Unfortunately, we have to work
                                // around an oddity in the way PETSc
                                // and some gcc versions interact. If
                                // we use PETSc's MPI dummy
                                // implementation, it expands the
                                // calls to the two MPI functions
                                // basically as ``(n_jobs=1, 0)'',
                                // i.e. it assigns the number one to
                                // the variable holding the number of
                                // jobs, and then uses the comma
                                // operator to let the entire
                                // expression have the value zero. The
                                // latter is important, since
                                // ``MPI_Comm_size'' returns an error
                                // code that we may want to check (we
                                // don't here, but one could in
                                // principle), and the trick with the
                                // comma operator makes sure that both
                                // the number of jobs is correctly
                                // assigned, and the return value is
                                // zero. Unfortunately, if some recent
                                // versions of gcc detect that the
                                // comma expression just stands by
                                // itself, i.e. the result is not
                                // assigned to another variable, then
                                // they warn ``right-hand operand of
                                // comma has no effect''. This
                                // unwanted side effect can be
                                // suppressed by casting the result of
                                // the entire expression to type
                                // ``void'' -- not beautiful, but
                                // helps calming down unwarranted
                                // compiler warnings...
    unsigned int n_mpi_processes (const MPI_Comm &mpi_communicator)
    {
      int n_jobs=1;
      (void) MPI_Comm_size (mpi_communicator, &n_jobs);

      return n_jobs;
    }

    unsigned int this_mpi_process (const MPI_Comm &mpi_communicator)
    {
      int rank=0;
      (void) MPI_Comm_rank (mpi_communicator, &rank);

      return rank;
    }

    MPI_Comm duplicate_communicator (const MPI_Comm &mpi_communicator)
    {
      MPI_Comm new_communicator;
      MPI_Comm_dup (mpi_communicator, &new_communicator);
      return new_communicator;
    }

    std::vector<unsigned int>
    compute_point_to_point_communication_pattern (const MPI_Comm & mpi_comm,
                                                  const std::vector<unsigned int> & destinations)
    {
      unsigned int myid = Utilities::MPI::this_mpi_process(mpi_comm);
      unsigned int n_procs = Utilities::MPI::n_mpi_processes(mpi_comm);

      for (unsigned int i=0; i<destinations.size(); ++i)
        {
          Assert (destinations[i] < n_procs,
                  ExcIndexRange (destinations[i], 0, n_procs));
          Assert (destinations[i] != myid,
                  ExcMessage ("There is no point in communicating with ourselves."));
        }

                                       // let all processors
                                       // communicate the maximal
                                       // number of destinations they
                                       // have
      const unsigned int max_n_destinations
        = Utilities::MPI::max (destinations.size(), mpi_comm);

                                       // now that we know the number
                                       // of data packets every
                                       // processor wants to send, set
                                       // up a buffer with the maximal
                                       // size and copy our
                                       // destinations in there,
                                       // padded with -1's
      std::vector<unsigned int> my_destinations(max_n_destinations,
                                                numbers::invalid_unsigned_int);
      std::copy (destinations.begin(), destinations.end(),
                 my_destinations.begin());

                                       // now exchange these (we could
                                       // communicate less data if we
                                       // used MPI_Allgatherv, but
                                       // we'd have to communicate
                                       // my_n_destinations to all
                                       // processors in this case,
                                       // which is more expensive than
                                       // the reduction operation
                                       // above in MPI_Allreduce)
      std::vector<unsigned int> all_destinations (max_n_destinations * n_procs);
      MPI_Allgather (&my_destinations[0], max_n_destinations, MPI_UNSIGNED,
                     &all_destinations[0], max_n_destinations, MPI_UNSIGNED,
                     mpi_comm);

                                       // now we know who is going to
                                       // communicate with
                                       // whom. collect who is going
                                       // to communicate with us!
      std::vector<unsigned int> origins;
      for (unsigned int i=0; i<n_procs; ++i)
        for (unsigned int j=0; j<max_n_destinations; ++j)
          if (all_destinations[i*max_n_destinations + j] == myid)
            origins.push_back (i);
          else if (all_destinations[i*max_n_destinations + j] ==
                   numbers::invalid_unsigned_int)
            break;

      return origins;
    }

    namespace
    {
                                       // custom MIP_Op for
                                       // calculate_collective_mpi_min_max_avg
      void max_reduce ( const void * in_lhs_,
                        void * inout_rhs_,
                        int * len,
                        MPI_Datatype * )
      {
        const MinMaxAvg * in_lhs = static_cast<const MinMaxAvg*>(in_lhs_);
        MinMaxAvg * inout_rhs = static_cast<MinMaxAvg*>(inout_rhs_);

        Assert(*len==1, ExcInternalError());

        inout_rhs->sum += in_lhs->sum;
        if (inout_rhs->min>in_lhs->min)
          {
            inout_rhs->min = in_lhs->min;
            inout_rhs->min_index = in_lhs->min_index;
          }
        else if (inout_rhs->min == in_lhs->min)
          { // choose lower cpu index when tied to make operator cumutative
            if (inout_rhs->min_index > in_lhs->min_index)
              inout_rhs->min_index = in_lhs->min_index;
          }

        if (inout_rhs->max < in_lhs->max)
          {
          inout_rhs->max = in_lhs->max;
          inout_rhs->max_index = in_lhs->max_index;
          }
        else if (inout_rhs->max == in_lhs->max)
          { // choose lower cpu index when tied to make operator cumutative
            if (inout_rhs->max_index > in_lhs->max_index)
              inout_rhs->max_index = in_lhs->max_index;
          }
      }
    }

    MinMaxAvg
    min_max_avg(const double my_value,
                const MPI_Comm &mpi_communicator)
    {
      MinMaxAvg result;

      const unsigned int my_id
        = dealii::Utilities::MPI::this_mpi_process(mpi_communicator);
      const unsigned int numproc
        = dealii::Utilities::MPI::n_mpi_processes(mpi_communicator);

      MPI_Op op;
      int ierr = MPI_Op_create((MPI_User_function *)&max_reduce, true, &op);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      MinMaxAvg in;
      in.sum = in.min = in.max = my_value;
      in.min_index = in.max_index = my_id;

      MPI_Datatype type;
      int lengths[]={3,2};
      MPI_Aint displacements[]={0,offsetof(MinMaxAvg, min_index)};
      MPI_Datatype types[]={MPI_DOUBLE, MPI_INT};

      ierr = MPI_Type_struct(2, lengths, displacements, types, &type);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Type_commit(&type);
      ierr = MPI_Allreduce (&in, &result, 1, type, op, mpi_communicator);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Type_free (&type);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Op_free(&op);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      result.avg = result.sum / numproc;

      return result;
    }

#else

    unsigned int n_mpi_processes (const MPI_Comm &)
    {
      return 1;
    }

    unsigned int this_mpi_process (const MPI_Comm &)
    {
      return 0;
    }

    MPI_Comm duplicate_communicator (const MPI_Comm &mpi_communicator)
    {
      return mpi_communicator;
    }

    MinMaxAvg
    min_max_avg(const double my_value,
                const MPI_Comm &)
    {
      MinMaxAvg result;

      result.sum = my_value;
      result.avg = my_value;
      result.min = my_value;
      result.max = my_value;
      result.min_index = 0;
      result.max_index = 0;

      return result;
    }

#endif

    MPI_InitFinalize::MPI_InitFinalize (int    &argc,
                                        char** &argv)
                    :
                    owns_mpi (true)
    {
      static bool constructor_has_already_run = false;
      Assert (constructor_has_already_run == false,
              ExcMessage ("You can only create a single object of this class "
                          "in a program since it initializes the MPI system."));

#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
      // if we have PETSc, we will initialize it and let it handle MPI.
      // Otherwise, we will do it.
#ifdef DEAL_II_USE_PETSC
      PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
#else
      int MPI_has_been_started = 0;
      MPI_Initialized(&MPI_has_been_started);
      AssertThrow (MPI_has_been_started == 0,
                   ExcMessage ("MPI error. You can only start MPI once!"));

      int mpi_err;
      mpi_err = MPI_Init (&argc, &argv);
      AssertThrow (mpi_err == 0,
                   ExcMessage ("MPI could not be initialized."));
#endif
#else
                                       // make sure the compiler doesn't warn
                                       // about these variables
      (void)argc;
      (void)argv;
#endif

      constructor_has_already_run = true;
    }

    MPI_InitFinalize::~MPI_InitFinalize()
    {
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI

#  if defined(DEAL_II_USE_TRILINOS) && !defined(__APPLE__)
                                       // make memory pool release all
                                       // vectors that are no longer
                                       // used at this point. this is
                                       // relevant because the static
                                       // object destructors run for
                                       // these vectors at the end of
                                       // the program would run after
                                       // MPI_Finalize is called,
                                       // leading to errors
                                       //
                                       // TODO: On Mac OS X, shared libs can
                                       // only depend on other libs listed
                                       // later on the command line. This
                                       // means that libbase can't depend on
                                       // liblac, and we can't destroy the
                                       // memory pool here as long as we have
                                       // separate libraries. Consequently,
                                       // the #ifdef above. Deal will then
                                       // just continue to seg fault upon
                                       // completion of main()
      GrowingVectorMemory<TrilinosWrappers::MPI::Vector>
        ::release_unused_memory ();
      GrowingVectorMemory<TrilinosWrappers::MPI::BlockVector>
        ::release_unused_memory ();
#  endif

#ifdef DEAL_II_USE_PETSC
      PetscFinalize();
#else

      int mpi_err = 0;

      int MPI_has_been_started = 0;
      MPI_Initialized(&MPI_has_been_started);
      if (Utilities::System::program_uses_mpi() == true && owns_mpi == true &&
          MPI_has_been_started != 0)
        {
          if (std::uncaught_exception())
            {
              std::cerr << "ERROR: Uncaught exception in MPI_InitFinalize on proc "
                        << this_mpi_process(MPI_COMM_WORLD)
                        << ". Skipping MPI_Finalize() to avoid a deadlock."
                        << std::endl;
            }
          else
            mpi_err = MPI_Finalize();
        }

      AssertThrow (mpi_err == 0,
                   ExcMessage ("An error occurred while calling MPI_Finalize()"));
#endif
#endif
    }

  } // end of namespace MPI

} // end of namespace Utilities

DEAL_II_NAMESPACE_CLOSE
<commit_msg>destroy GrowingVectorMemory with PETSc objects at the end<commit_after>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/mpi.h>
#include <deal.II/base/utilities.h>
#include <deal.II/base/exceptions.h>

#include <cstddef>
#include <iostream>

#ifdef DEAL_II_USE_TRILINOS
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <Epetra_MpiComm.h>
#    include <deal.II/lac/vector_memory.h>
#    include <deal.II/lac/trilinos_vector.h>
#    include <deal.II/lac/trilinos_block_vector.h>
#  endif
#endif

#ifdef DEAL_II_USE_PETSC
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <petscsys.h>
#include <deal.II/lac/petsc_block_vector.h>
#include <deal.II/lac/petsc_parallel_block_vector.h>
#include <deal.II/lac/petsc_vector.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#  endif
#endif

DEAL_II_NAMESPACE_OPEN

namespace Utilities
{

  namespace MPI
  {
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
                                // Unfortunately, we have to work
                                // around an oddity in the way PETSc
                                // and some gcc versions interact. If
                                // we use PETSc's MPI dummy
                                // implementation, it expands the
                                // calls to the two MPI functions
                                // basically as ``(n_jobs=1, 0)'',
                                // i.e. it assigns the number one to
                                // the variable holding the number of
                                // jobs, and then uses the comma
                                // operator to let the entire
                                // expression have the value zero. The
                                // latter is important, since
                                // ``MPI_Comm_size'' returns an error
                                // code that we may want to check (we
                                // don't here, but one could in
                                // principle), and the trick with the
                                // comma operator makes sure that both
                                // the number of jobs is correctly
                                // assigned, and the return value is
                                // zero. Unfortunately, if some recent
                                // versions of gcc detect that the
                                // comma expression just stands by
                                // itself, i.e. the result is not
                                // assigned to another variable, then
                                // they warn ``right-hand operand of
                                // comma has no effect''. This
                                // unwanted side effect can be
                                // suppressed by casting the result of
                                // the entire expression to type
                                // ``void'' -- not beautiful, but
                                // helps calming down unwarranted
                                // compiler warnings...
    unsigned int n_mpi_processes (const MPI_Comm &mpi_communicator)
    {
      int n_jobs=1;
      (void) MPI_Comm_size (mpi_communicator, &n_jobs);

      return n_jobs;
    }

    unsigned int this_mpi_process (const MPI_Comm &mpi_communicator)
    {
      int rank=0;
      (void) MPI_Comm_rank (mpi_communicator, &rank);

      return rank;
    }

    MPI_Comm duplicate_communicator (const MPI_Comm &mpi_communicator)
    {
      MPI_Comm new_communicator;
      MPI_Comm_dup (mpi_communicator, &new_communicator);
      return new_communicator;
    }

    std::vector<unsigned int>
    compute_point_to_point_communication_pattern (const MPI_Comm & mpi_comm,
                                                  const std::vector<unsigned int> & destinations)
    {
      unsigned int myid = Utilities::MPI::this_mpi_process(mpi_comm);
      unsigned int n_procs = Utilities::MPI::n_mpi_processes(mpi_comm);

      for (unsigned int i=0; i<destinations.size(); ++i)
        {
          Assert (destinations[i] < n_procs,
                  ExcIndexRange (destinations[i], 0, n_procs));
          Assert (destinations[i] != myid,
                  ExcMessage ("There is no point in communicating with ourselves."));
        }

                                       // let all processors
                                       // communicate the maximal
                                       // number of destinations they
                                       // have
      const unsigned int max_n_destinations
        = Utilities::MPI::max (destinations.size(), mpi_comm);

                                       // now that we know the number
                                       // of data packets every
                                       // processor wants to send, set
                                       // up a buffer with the maximal
                                       // size and copy our
                                       // destinations in there,
                                       // padded with -1's
      std::vector<unsigned int> my_destinations(max_n_destinations,
                                                numbers::invalid_unsigned_int);
      std::copy (destinations.begin(), destinations.end(),
                 my_destinations.begin());

                                       // now exchange these (we could
                                       // communicate less data if we
                                       // used MPI_Allgatherv, but
                                       // we'd have to communicate
                                       // my_n_destinations to all
                                       // processors in this case,
                                       // which is more expensive than
                                       // the reduction operation
                                       // above in MPI_Allreduce)
      std::vector<unsigned int> all_destinations (max_n_destinations * n_procs);
      MPI_Allgather (&my_destinations[0], max_n_destinations, MPI_UNSIGNED,
                     &all_destinations[0], max_n_destinations, MPI_UNSIGNED,
                     mpi_comm);

                                       // now we know who is going to
                                       // communicate with
                                       // whom. collect who is going
                                       // to communicate with us!
      std::vector<unsigned int> origins;
      for (unsigned int i=0; i<n_procs; ++i)
        for (unsigned int j=0; j<max_n_destinations; ++j)
          if (all_destinations[i*max_n_destinations + j] == myid)
            origins.push_back (i);
          else if (all_destinations[i*max_n_destinations + j] ==
                   numbers::invalid_unsigned_int)
            break;

      return origins;
    }

    namespace
    {
                                       // custom MIP_Op for
                                       // calculate_collective_mpi_min_max_avg
      void max_reduce ( const void * in_lhs_,
                        void * inout_rhs_,
                        int * len,
                        MPI_Datatype * )
      {
        const MinMaxAvg * in_lhs = static_cast<const MinMaxAvg*>(in_lhs_);
        MinMaxAvg * inout_rhs = static_cast<MinMaxAvg*>(inout_rhs_);

        Assert(*len==1, ExcInternalError());

        inout_rhs->sum += in_lhs->sum;
        if (inout_rhs->min>in_lhs->min)
          {
            inout_rhs->min = in_lhs->min;
            inout_rhs->min_index = in_lhs->min_index;
          }
        else if (inout_rhs->min == in_lhs->min)
          { // choose lower cpu index when tied to make operator cumutative
            if (inout_rhs->min_index > in_lhs->min_index)
              inout_rhs->min_index = in_lhs->min_index;
          }

        if (inout_rhs->max < in_lhs->max)
          {
          inout_rhs->max = in_lhs->max;
          inout_rhs->max_index = in_lhs->max_index;
          }
        else if (inout_rhs->max == in_lhs->max)
          { // choose lower cpu index when tied to make operator cumutative
            if (inout_rhs->max_index > in_lhs->max_index)
              inout_rhs->max_index = in_lhs->max_index;
          }
      }
    }

    MinMaxAvg
    min_max_avg(const double my_value,
                const MPI_Comm &mpi_communicator)
    {
      MinMaxAvg result;

      const unsigned int my_id
        = dealii::Utilities::MPI::this_mpi_process(mpi_communicator);
      const unsigned int numproc
        = dealii::Utilities::MPI::n_mpi_processes(mpi_communicator);

      MPI_Op op;
      int ierr = MPI_Op_create((MPI_User_function *)&max_reduce, true, &op);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      MinMaxAvg in;
      in.sum = in.min = in.max = my_value;
      in.min_index = in.max_index = my_id;

      MPI_Datatype type;
      int lengths[]={3,2};
      MPI_Aint displacements[]={0,offsetof(MinMaxAvg, min_index)};
      MPI_Datatype types[]={MPI_DOUBLE, MPI_INT};

      ierr = MPI_Type_struct(2, lengths, displacements, types, &type);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Type_commit(&type);
      ierr = MPI_Allreduce (&in, &result, 1, type, op, mpi_communicator);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Type_free (&type);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      ierr = MPI_Op_free(&op);
      AssertThrow(ierr == MPI_SUCCESS, ExcInternalError());

      result.avg = result.sum / numproc;

      return result;
    }

#else

    unsigned int n_mpi_processes (const MPI_Comm &)
    {
      return 1;
    }

    unsigned int this_mpi_process (const MPI_Comm &)
    {
      return 0;
    }

    MPI_Comm duplicate_communicator (const MPI_Comm &mpi_communicator)
    {
      return mpi_communicator;
    }

    MinMaxAvg
    min_max_avg(const double my_value,
                const MPI_Comm &)
    {
      MinMaxAvg result;

      result.sum = my_value;
      result.avg = my_value;
      result.min = my_value;
      result.max = my_value;
      result.min_index = 0;
      result.max_index = 0;

      return result;
    }

#endif

    MPI_InitFinalize::MPI_InitFinalize (int    &argc,
                                        char** &argv)
                    :
                    owns_mpi (true)
    {
      static bool constructor_has_already_run = false;
      Assert (constructor_has_already_run == false,
              ExcMessage ("You can only create a single object of this class "
                          "in a program since it initializes the MPI system."));

#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
      // if we have PETSc, we will initialize it and let it handle MPI.
      // Otherwise, we will do it.
#ifdef DEAL_II_USE_PETSC
      PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
#else
      int MPI_has_been_started = 0;
      MPI_Initialized(&MPI_has_been_started);
      AssertThrow (MPI_has_been_started == 0,
                   ExcMessage ("MPI error. You can only start MPI once!"));

      int mpi_err;
      mpi_err = MPI_Init (&argc, &argv);
      AssertThrow (mpi_err == 0,
                   ExcMessage ("MPI could not be initialized."));
#endif
#else
                                       // make sure the compiler doesn't warn
                                       // about these variables
      (void)argc;
      (void)argv;
#endif

      constructor_has_already_run = true;
    }

    MPI_InitFinalize::~MPI_InitFinalize()
    {
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI

                                       // make memory pool release all
                                       // vectors that are no longer
                                       // used at this point. this is
                                       // relevant because the static
                                       // object destructors run for
                                       // these vectors at the end of
                                       // the program would run after
                                       // MPI_Finalize is called,
                                       // leading to errors
                                       //
#  if defined(DEAL_II_USE_TRILINOS) && !defined(__APPLE__)
                                       // TODO: On Mac OS X, shared libs can
                                       // only depend on other libs listed
                                       // later on the command line. This
                                       // means that libbase can't depend on
                                       // liblac, and we can't destroy the
                                       // memory pool here as long as we have
                                       // separate libraries. Consequently,
                                       // the #ifdef above. Deal will then
                                       // just continue to seg fault upon
                                       // completion of main()
      GrowingVectorMemory<TrilinosWrappers::MPI::Vector>
        ::release_unused_memory ();
      GrowingVectorMemory<TrilinosWrappers::MPI::BlockVector>
        ::release_unused_memory ();
#  endif

				       // Same for PETSc.
#ifdef DEAL_II_USE_PETSC
      GrowingVectorMemory<PETScWrappers::MPI::Vector>
        ::release_unused_memory ();
      GrowingVectorMemory<PETScWrappers::MPI::BlockVector>
        ::release_unused_memory ();
      GrowingVectorMemory<PETScWrappers::Vector>
        ::release_unused_memory ();
      GrowingVectorMemory<PETScWrappers::BlockVector>
        ::release_unused_memory ();

				       // now end PETSc.
      PetscFinalize();
#else

      int mpi_err = 0;

      int MPI_has_been_started = 0;
      MPI_Initialized(&MPI_has_been_started);
      if (Utilities::System::program_uses_mpi() == true && owns_mpi == true &&
          MPI_has_been_started != 0)
        {
          if (std::uncaught_exception())
            {
              std::cerr << "ERROR: Uncaught exception in MPI_InitFinalize on proc "
                        << this_mpi_process(MPI_COMM_WORLD)
                        << ". Skipping MPI_Finalize() to avoid a deadlock."
                        << std::endl;
            }
          else
            mpi_err = MPI_Finalize();
        }

      AssertThrow (mpi_err == 0,
                   ExcMessage ("An error occurred while calling MPI_Finalize()"));
#endif
#endif
    }

  } // end of namespace MPI

} // end of namespace Utilities

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>


<commit_before>/* rsspp - Copyright (C) 2008 Andreas Krennmair <ak@newsbeuter.org>
 * Licensed under the MIT/X Consortium License. See file LICENSE
 * for more information.
 */

#include <rsspp.h>
#include <rsspp_internal.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include <logger.h>

using namespace newsbeuter;

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	std::string * pbuf = static_cast<std::string *>(userp);
	pbuf->append(static_cast<const char *>(buffer), size * nmemb);
	return size * nmemb;
}

namespace rsspp {

parser::parser(unsigned int timeout, const char * user_agent, const char * proxy, const char * proxy_auth)
	: to(timeout), ua(user_agent), prx(proxy), prxauth(proxy_auth), doc(0) {
}

parser::~parser() {
	if (doc)
		xmlFreeDoc(doc);
	xmlCleanupParser();
}

feed parser::parse_url(const std::string& url) {
	std::string buf;
	CURLcode ret;

	CURL * easyhandle = curl_easy_init();
	if (!easyhandle) {
		throw exception(0, "curl_easy_init() failed");
	}

	if (ua) {
		curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, ua);
	}
	curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str());
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf);
	curl_easy_setopt(easyhandle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FAILONERROR, 1);
	curl_easy_setopt(easyhandle, CURLOPT_ENCODING, "gzip, deflate");
	if (to != 0)
		curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, to);

	if (prx)
		curl_easy_setopt(easyhandle, CURLOPT_PROXY, prx);

	if (prxauth)
		curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, prxauth);

	ret = curl_easy_perform(easyhandle);
	curl_easy_cleanup(easyhandle);

	GetLogger().log(LOG_DEBUG, "rsspp::parser::parse_url: ret = %d", ret);

	if (ret != 0) {
		throw exception(0, "curl_easy_perform error");
	}

	GetLogger().log(LOG_INFO, "parser::parse_url: retrieved data for %s: %s", url.c_str(), buf.c_str());

	if (buf.length() > 0)
		return parse_buffer(buf.c_str(), buf.length());

	return feed();
}

feed parser::parse_buffer(const char * buffer, size_t size, const char * url) {
	doc = xmlReadMemory(buffer, size, url, NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(0, "unable to parse buffer");
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	GetLogger().log(LOG_INFO, "parser::parse_buffer: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_file(const std::string& filename) {
	doc = xmlReadFile(filename.c_str(), NULL, 0);
	if (doc == NULL) {
		throw exception(0, "unable to parse file");
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	GetLogger().log(LOG_INFO, "parser::parse_file: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_xmlnode(xmlNode* node) {
	feed f;

	if (node) {
		if (node->name && node->type == XML_ELEMENT_NODE) {
			if (strcmp((const char *)node->name, "rss")==0) {
				const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version");
				if (!version) {
					xmlFree((void *)version);
					throw exception(0, "no RSS version");
				}
				if (strcmp(version, "0.91")==0)
					f.rss_version = RSS_0_91;
				else if (strcmp(version, "0.92")==0)
					f.rss_version = RSS_0_92;
				else if (strcmp(version, "2.0")==0)
					f.rss_version = RSS_2_0;
				else {
					xmlFree((void *)version);
					throw exception(0, "invalid RSS version");
				}
				xmlFree((void *)version);
			} else if (strcmp((const char *)node->name, "RDF")==0) {
				f.rss_version = RSS_1_0;
			} else if (strcmp((const char *)node->name, "feed")==0) {
				char * xmlns = (char *)xmlGetProp(node, (const xmlChar *)"xmlns");
				if (xmlns) {
					if (strcmp(xmlns, ATOM_0_3_URI)==0) {
						f.rss_version = ATOM_0_3;
					} else if (strcmp(xmlns, ATOM_1_0_URI)==0) {
						f.rss_version = ATOM_1_0;
					} else {
						xmlFree(xmlns);
						throw exception(0, "invalid Atom version");
					}
					xmlFree(xmlns);
				} else {
					xmlFree(xmlns);
					throw exception(0, "no Atom version");
				}
			}

			std::tr1::shared_ptr<rss_parser> parser = rss_parser_factory::get_object(f);

			try {
				parser->parse_feed(f, node);
			} catch (exception& e) {
				throw e;
			}
		}
	} else {
		// TODO: throw exception
	}

	return f;
}

void parser::global_init() {
	LIBXML_TEST_VERSION
}

void parser::global_cleanup() {
	xmlCleanupParser();
}

}
<commit_msg>fix Atom version recognition.<commit_after>/* rsspp - Copyright (C) 2008 Andreas Krennmair <ak@newsbeuter.org>
 * Licensed under the MIT/X Consortium License. See file LICENSE
 * for more information.
 */

#include <rsspp.h>
#include <rsspp_internal.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include <logger.h>

using namespace newsbeuter;

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	std::string * pbuf = static_cast<std::string *>(userp);
	pbuf->append(static_cast<const char *>(buffer), size * nmemb);
	return size * nmemb;
}

namespace rsspp {

parser::parser(unsigned int timeout, const char * user_agent, const char * proxy, const char * proxy_auth)
	: to(timeout), ua(user_agent), prx(proxy), prxauth(proxy_auth), doc(0) {
}

parser::~parser() {
	if (doc)
		xmlFreeDoc(doc);
	xmlCleanupParser();
}

feed parser::parse_url(const std::string& url) {
	std::string buf;
	CURLcode ret;

	CURL * easyhandle = curl_easy_init();
	if (!easyhandle) {
		throw exception(0, "curl_easy_init() failed");
	}

	if (ua) {
		curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, ua);
	}
	curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str());
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf);
	curl_easy_setopt(easyhandle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(easyhandle, CURLOPT_FAILONERROR, 1);
	curl_easy_setopt(easyhandle, CURLOPT_ENCODING, "gzip, deflate");
	if (to != 0)
		curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, to);

	if (prx)
		curl_easy_setopt(easyhandle, CURLOPT_PROXY, prx);

	if (prxauth)
		curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, prxauth);

	ret = curl_easy_perform(easyhandle);
	curl_easy_cleanup(easyhandle);

	GetLogger().log(LOG_DEBUG, "rsspp::parser::parse_url: ret = %d", ret);

	if (ret != 0) {
		throw exception(0, "curl_easy_perform error");
	}

	GetLogger().log(LOG_INFO, "parser::parse_url: retrieved data for %s: %s", url.c_str(), buf.c_str());

	if (buf.length() > 0)
		return parse_buffer(buf.c_str(), buf.length());

	return feed();
}

feed parser::parse_buffer(const char * buffer, size_t size, const char * url) {
	doc = xmlReadMemory(buffer, size, url, NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (doc == NULL) {
		throw exception(0, "unable to parse buffer");
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	GetLogger().log(LOG_INFO, "parser::parse_buffer: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_file(const std::string& filename) {
	doc = xmlReadFile(filename.c_str(), NULL, 0);
	if (doc == NULL) {
		throw exception(0, "unable to parse file");
	}

	xmlNode* root_element = xmlDocGetRootElement(doc);

	feed f = parse_xmlnode(root_element);

	if (doc->encoding) {
		f.encoding = (const char *)doc->encoding;
	}

	GetLogger().log(LOG_INFO, "parser::parse_file: encoding = %s", f.encoding.c_str());

	return f;
}

feed parser::parse_xmlnode(xmlNode* node) {
	feed f;

	if (node) {
		if (node->name && node->type == XML_ELEMENT_NODE) {
			if (strcmp((const char *)node->name, "rss")==0) {
				const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version");
				if (!version) {
					xmlFree((void *)version);
					throw exception(0, "no RSS version");
				}
				if (strcmp(version, "0.91")==0)
					f.rss_version = RSS_0_91;
				else if (strcmp(version, "0.92")==0)
					f.rss_version = RSS_0_92;
				else if (strcmp(version, "2.0")==0)
					f.rss_version = RSS_2_0;
				else {
					xmlFree((void *)version);
					throw exception(0, "invalid RSS version");
				}
				xmlFree((void *)version);
			} else if (strcmp((const char *)node->name, "RDF")==0) {
				f.rss_version = RSS_1_0;
			} else if (strcmp((const char *)node->name, "feed")==0) {
				if (node->ns && node->ns->href) {
					if (strcmp((const char *)node->ns->href, ATOM_0_3_URI)==0) {
						f.rss_version = ATOM_0_3;
					} else if (strcmp((const char *)node->ns->href, ATOM_1_0_URI)==0) {
						f.rss_version = ATOM_1_0;
					} else {
						throw exception(0, "invalid Atom version");
					}
				} else {
					throw exception(0, "no Atom version");
				}
			}

			std::tr1::shared_ptr<rss_parser> parser = rss_parser_factory::get_object(f);

			try {
				parser->parse_feed(f, node);
			} catch (exception& e) {
				throw e;
			}
		}
	} else {
		// TODO: throw exception
	}

	return f;
}

void parser::global_init() {
	LIBXML_TEST_VERSION
}

void parser::global_cleanup() {
	xmlCleanupParser();
}

}
<|endoftext|>


<commit_before>// @(#)root/cintex:$Id$
// Author: Pere Mato 2005

// Copyright CERN, CH-1211 Geneva 23, 2004-2005, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#include "Reflex/Reflex.h"
#include "Reflex/Tools.h"
#include "Cintex/Cintex.h"
#include "CINTdefs.h"
#include "CINTVariableBuilder.h"
#include "CINTScopeBuilder.h"
#include "CINTCommentBuffer.h"

#include "Api.h"

#include <iomanip>
#include <sstream>

using namespace ROOT::Reflex;
using namespace std;

namespace ROOT { namespace Cintex {

   CINTVariableBuilder::CINTVariableBuilder(const ROOT::Reflex::Member& m)
      : fVariable(m) {
      // Default constructor.
   }

   CINTVariableBuilder::~CINTVariableBuilder() {
      // Destructor.
   }

   void CINTVariableBuilder::Setup() {
      // Setup variable info.
      CINTScopeBuilder::Setup(fVariable.TypeOf());

      Scope scope = fVariable.DeclaringScope();
      CINTScopeBuilder::Setup(scope);

      bool global = scope.IsTopScope();

      if ( global ) {
         ::G__resetplocal();
      }
      else {
         string sname = scope.Name(SCOPED);
         int stagnum = ::G__defined_tagname(sname.c_str(), 2);
         ::G__tag_memvar_setup(stagnum);
      }

      Setup(fVariable);

      if ( global ) {
         ::G__resetglobalenv();
      }
      else {
         ::G__tag_memvar_reset();
      }
      return;
   }

   void CINTVariableBuilder::Setup(const Member& dm ) {
      // Setup variable info.
      char* comment = NULL;

      const char* ref_t = "pool::Reference";
      const char* tok_t = "pool::Token";

      Type fClass = Type::ByName(dm.DeclaringScope().Name(SCOPED));
      string fName(CintName(fClass));

      std::string cm = dm.Properties().HasProperty("comment") ?
         dm.Properties().PropertyAsString("comment") : std::string("");

      Type t = dm.TypeOf();
      while ( t.IsTypedef() ) t = t.ToType();
      if ( !t && dm.IsTransient() )  {
         // Before giving up, let's ask CINT:
         int tagnum = G__defined_tagname(t.Name().c_str(), 2);

         if (tagnum < 0) {
            if( Cintex::Debug() ) cout << "Cintex: Ignore transient member: "
               << dm.Name(SCOPED) << " [No valid reflection class]"
               << " " << t.Name() << endl;
            return;
         }
      }
      else if ( !t )  {
         if( Cintex::Debug() > 0 )  {
            cout << "Cintex: WARNING: Member: "
                 << dm.Name(SCOPED) << " [No valid reflection class]" << endl;
         }
         //throw std::runtime_error("Member: "+fName+"::"+dm.Name()+" [No valid reflection class]");
      }
      //--- Add the necessary artificial comments ------
      if ( dm.IsTransient() ||
           IsSTL(fName) ||
           IsTypeOf(fClass, ref_t) ||
           IsTypeOf(fClass, tok_t) )  {
         char* com = new char[cm.length()+4];
         ::sprintf(com,"! %s",cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }
      else if ( (t.IsClass() || t.IsStruct()) &&
                (IsTypeOf(t,ref_t) || IsTypeOf(t,tok_t)) )  {
         char* com = new char[cm.length()+4];
         ::sprintf(com,"|| %s",cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }
      else if ( !cm.empty() )  {
         char* com = new char[cm.length()+4];
         ::strcpy(com, cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }
      Indirection  indir = IndirectionGet(dm.TypeOf());
      CintTypeDesc type = CintType(indir.second);
      string dname = dm.Properties().HasProperty("ioname") ? dm.Properties().PropertyAsString("ioname") : dm.Name();
      ostringstream ost;
      if ( t.IsArray() ) ost << dname << "[" << t.ArrayLength() << "]=";
      else               ost << dname << "=";
      string expr = ost.str();
      int member_type     = type.first;
      int member_indir    = 0;
      int member_tagnum   = -1;
      int member_typnum   = -1;
      int member_isstatic = G__AUTO;
      if (dm.IsStatic() || dm.DeclaringScope().IsNamespace())
         member_isstatic = G__LOCALSTATIC;
      switch(indir.first)  {
      case 0:
         break;
      case 1:
         member_type -= 'a'-'A';            // if pointer: 'f' -> 'F' etc.
         break;
      default:
         member_type -= 'a'-'A';            // if pointer: 'f' -> 'F' etc.
         member_indir = indir.first;
         break;
      }

      if ( type.first == 'u' )  {
         // Large integer definition depends of the platform
#if defined(_WIN32) && !defined(__CINT__)
         typedef __int64 longlong;
         typedef unsigned __int64 ulonglong;
#else
         typedef long long int longlong; /* */
         typedef unsigned long long int /**/ ulonglong;
#endif

         //dependencies.push_back(indir.second);
         member_tagnum = dm.Properties().HasProperty("iotype") ? CintTag(dm.Properties().PropertyAsString("iotype")) : CintTag(type.second);
         if ( typeid(longlong) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__LONGLONG);
         else if ( typeid(ulonglong) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__ULONGLONG);
         else if ( typeid(long double) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__LONGDOUBLE);
      }

      int member_access = 0;
      if ( dm.IsPrivate() )        member_access = G__PRIVATE;
      else if ( dm.IsProtected() ) member_access = G__PROTECTED;
      else if ( dm.IsPublic() )    member_access = G__PUBLIC;

      if ( Cintex::Debug() > 2 )  {
         std::cout
            << std::setw(24) << std::left << "Cintex: declareField>"
            << "  [" << char(member_type)
            << "," << std::right << std::setw(3) << dm.Offset()
            << "," << std::right << std::setw(2) << member_indir
            << "," << std::right << std::setw(3) << member_tagnum
            << "] "
            << (dm.TypeOf().IsConst() ? "const " : "")
            << std::left << std::setw(7)
            << (G__AUTO==member_isstatic ? "auto " : "static ")
            << std::left << std::setw(24) << dname
            << " \"" << (char*)(comment ? comment : "(None)") << "\""
            << std::endl
            << std::setw(24) << std::left << "Cintex: declareField>"
            << "  Type:"
            << std::left << std::setw(24) << ("[" + dm.Properties().HasProperty("iotype") ? dm.Properties().PropertyAsString("iotype") : t.Name(SCOPED) + "]")
            << " DeclBy:" << fClass.Name(SCOPED)
            << std::endl;
      }
      ::G__memvar_setup((void*)dm.Offset(),                         // p
                        member_type,                                // type
                        member_indir,                               // indirection
                        dm.TypeOf().IsConst(),                        // const
                        member_tagnum,                              // tagnum
                        member_typnum,                              // typenum
                        member_isstatic,                            // statictype
                        member_access,                              // accessin
                        expr.c_str(),                               // expression
                        0,                                          // define macro
                        comment                                     // comment
                        );
   }

}}
<commit_msg>Support for "iotype" property for non-structs. CMS request for streaming Double32_t even though GCCXML doesn't see it. NOTE that this still doesn't fix cases like   MyClass<std::vector<Double32_t> > which genreflex never sees (it sees only the version with double), so there's nothing to set the iotype on.<commit_after>// @(#)root/cintex:$Id$
// Author: Pere Mato 2005

// Copyright CERN, CH-1211 Geneva 23, 2004-2005, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#include "Reflex/Reflex.h"
#include "Reflex/Tools.h"
#include "Cintex/Cintex.h"
#include "CINTdefs.h"
#include "CINTVariableBuilder.h"
#include "CINTScopeBuilder.h"
#include "CINTCommentBuffer.h"

#include "Api.h"

#include <iomanip>
#include <sstream>

using namespace ROOT::Reflex;
using namespace std;

namespace ROOT { namespace Cintex {

   CINTVariableBuilder::CINTVariableBuilder(const ROOT::Reflex::Member& m)
      : fVariable(m) {
      // Default constructor.
   }

   CINTVariableBuilder::~CINTVariableBuilder() {
      // Destructor.
   }

   void CINTVariableBuilder::Setup() {
      // Setup variable info.
      CINTScopeBuilder::Setup(fVariable.TypeOf());

      Scope scope = fVariable.DeclaringScope();
      CINTScopeBuilder::Setup(scope);

      bool global = scope.IsTopScope();

      if ( global ) {
         ::G__resetplocal();
      }
      else {
         string sname = scope.Name(SCOPED);
         int stagnum = ::G__defined_tagname(sname.c_str(), 2);
         ::G__tag_memvar_setup(stagnum);
      }

      Setup(fVariable);

      if ( global ) {
         ::G__resetglobalenv();
      }
      else {
         ::G__tag_memvar_reset();
      }
      return;
   }

   void CINTVariableBuilder::Setup(const Member& dm ) {
      // Setup variable info.
      char* comment = NULL;

      const char* ref_t = "pool::Reference";
      const char* tok_t = "pool::Token";

      Type fClass = Type::ByName(dm.DeclaringScope().Name(SCOPED));
      string fName(CintName(fClass));

      std::string cm = dm.Properties().HasProperty("comment") ?
         dm.Properties().PropertyAsString("comment") : std::string("");

      Type dmType = dm.TypeOf();
      if (dm.Properties().HasProperty("iotype")) {
         dmType = Reflex::Type::ByName(dm.Properties().PropertyAsString("iotype"));
      }
      while ( dmType.IsTypedef() ) dmType = dmType.ToType();
      if ( !dmType && dm.IsTransient() )  {
         // Before giving up, let's ask CINT:
         int tagnum = G__defined_tagname(dmType.Name().c_str(), 2);

         if (tagnum < 0) {
            if( Cintex::Debug() ) cout << "Cintex: Ignore transient member: "
               << dm.Name(SCOPED) << " [No valid reflection class]"
               << " " << dmType.Name() << endl;
            return;
         }
      }
      else if ( !dmType )  {
         if( Cintex::Debug() > 0 )  {
            cout << "Cintex: WARNING: Member: "
                 << dm.Name(SCOPED) << " [No valid reflection class]" << endl;
         }
         //throw std::runtime_error("Member: "+fName+"::"+dm.Name()+" [No valid reflection class]");
      }
      //--- Add the necessary artificial comments ------
      if ( dm.IsTransient() ||
           IsSTL(fName) ||
           IsTypeOf(fClass, ref_t) ||
           IsTypeOf(fClass, tok_t) )  {
         char* com = new char[cm.length()+4];
         ::sprintf(com,"! %s",cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }
      else if ( (dmType.IsClass() || dmType.IsStruct()) &&
                (IsTypeOf(dmType,ref_t) || IsTypeOf(dmType,tok_t)) )  {
         char* com = new char[cm.length()+4];
         ::sprintf(com,"|| %s",cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }
      else if ( !cm.empty() )  {
         char* com = new char[cm.length()+4];
         ::strcpy(com, cm.c_str());
         comment = com;
         CommentBuffer::Instance().Add(comment);
      }

      Indirection  indir = IndirectionGet(dmType);
      CintTypeDesc type = CintType(indir.second);
      string dname = dm.Properties().HasProperty("ioname") ? dm.Properties().PropertyAsString("ioname") : dm.Name();
      ostringstream ost;
      if ( dmType.IsArray() ) ost << dname << "[" << dmType.ArrayLength() << "]=";
      else                    ost << dname << "=";
      string expr = ost.str();
      int member_type     = type.first;
      int member_indir    = 0;
      int member_tagnum   = -1;
      int member_typnum   = -1;
      int member_isstatic = G__AUTO;
      if (dm.IsStatic() || dm.DeclaringScope().IsNamespace())
         member_isstatic = G__LOCALSTATIC;
      switch(indir.first)  {
      case 0:
         break;
      case 1:
         member_type -= 'a'-'A';            // if pointer: 'f' -> 'F' etc.
         break;
      default:
         member_type -= 'a'-'A';            // if pointer: 'f' -> 'F' etc.
         member_indir = indir.first;
         break;
      }

      if ( type.first == 'u' )  {
         // Large integer definition depends of the platform
#if defined(_WIN32) && !defined(__CINT__)
         typedef __int64 longlong;
         typedef unsigned __int64 ulonglong;
#else
         typedef long long int longlong; /* */
         typedef unsigned long long int /**/ ulonglong;
#endif

         //dependencies.push_back(indir.second);
         member_tagnum = dm.Properties().HasProperty("iotype") ? CintTag(dm.Properties().PropertyAsString("iotype")) : CintTag(type.second);
         if ( typeid(longlong) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__LONGLONG);
         else if ( typeid(ulonglong) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__ULONGLONG);
         else if ( typeid(long double) == indir.second.TypeInfo() )
            ::G__loadlonglong(&member_tagnum, &member_typnum, G__LONGDOUBLE);
      }

      int member_access = 0;
      if ( dm.IsPrivate() )        member_access = G__PRIVATE;
      else if ( dm.IsProtected() ) member_access = G__PROTECTED;
      else if ( dm.IsPublic() )    member_access = G__PUBLIC;

      if ( Cintex::Debug() > 2 )  {
         std::cout
            << std::setw(24) << std::left << "Cintex: declareField>"
            << "  [" << char(member_type)
            << "," << std::right << std::setw(3) << dm.Offset()
            << "," << std::right << std::setw(2) << member_indir
            << "," << std::right << std::setw(3) << member_tagnum
            << "] "
            << (dmType.IsConst() ? "const " : "")
            << std::left << std::setw(7)
            << (G__AUTO==member_isstatic ? "auto " : "static ")
            << std::left << std::setw(24) << dname
            << " \"" << (char*)(comment ? comment : "(None)") << "\""
            << std::endl
            << std::setw(24) << std::left << "Cintex: declareField>"
            << "  Type:"
            << std::left << std::setw(24) << ("[" + dm.Properties().HasProperty("iotype") ? dm.Properties().PropertyAsString("iotype") : dmType.Name(SCOPED) + "]")
            << " DeclBy:" << fClass.Name(SCOPED)
            << std::endl;
      }
      ::G__memvar_setup((void*)dm.Offset(),                         // p
                        member_type,                                // type
                        member_indir,                               // indirection
                        dmType.IsConst(),                        // const
                        member_tagnum,                              // tagnum
                        member_typnum,                              // typenum
                        member_isstatic,                            // statictype
                        member_access,                              // accessin
                        expr.c_str(),                               // expression
                        0,                                          // define macro
                        comment                                     // comment
                        );
   }

}}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "nodeinstancemetaobject.h"

#include "objectnodeinstance.h"
#include <QSharedPointer>
#include <QMetaProperty>
#include <qnumeric.h>
#include <QDebug>

#include <private/qqmlengine_p.h>
#include <private/qqmlpropertycache_p.h>

namespace QmlDesigner {
namespace Internal {

static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList;

struct MetaPropertyData {
    inline QPair<QVariant, bool> &getDataRef(int idx) {
        while (m_data.count() <= idx)
            m_data << QPair<QVariant, bool>(QVariant(), false);
        return m_data[idx];
    }

    inline QVariant &getData(int idx) {
        QPair<QVariant, bool> &prop = getDataRef(idx);
        if (!prop.second) {
            prop.first = QVariant();
            prop.second = true;
        }
        return prop.first;
    }

    inline bool hasData(int idx) const {
        if (idx >= m_data.count())
            return false;
        return m_data[idx].second;
    }

    inline int count() { return m_data.count(); }

    QList<QPair<QVariant, bool> > m_data;
};

static bool constructedMetaData(const QQmlVMEMetaData* data)
{
    return data->varPropertyCount == 0
            && data->propertyCount == 0
            && data->aliasCount == 0
            && data->signalCount == 0
            && data->methodCount == 0;
}

static QQmlVMEMetaData* fakeMetaData()
{
    QQmlVMEMetaData* data = new QQmlVMEMetaData;
    data->varPropertyCount = 0;
    data->propertyCount = 0;
    data->aliasCount = 0;
    data->signalCount = 0;
    data->methodCount = 0;

    return data;
}

static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object)
{
    QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
    if (metaObject)
        return metaObject->metaData;

    return fakeMetaData();
}

static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine)
{
    QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
    if (metaObject)
        return metaObject->cache;

    return QQmlEnginePrivate::get(engine)->cache(object);
}

static QAbstractDynamicMetaObject *abstractDynamicMetaObject(QObject *object)
{
    QObjectPrivate *op = QObjectPrivate::get(object);
    if (op->metaObject)
        return static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
    return const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(object->metaObject()));
}

NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine)
{
    //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject
    QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object());
    QDynamicMetaObjectData *parent = op->metaObject;
    if (nodeInstanceMetaObjectList.contains(parent))
        return static_cast<NodeInstanceMetaObject *>(parent);

    return new NodeInstanceMetaObject(nodeInstance, engine);
}

NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine)
{
    //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject
    QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object());
    QDynamicMetaObjectData *parent = op->metaObject;
    if (nodeInstanceMetaObjectList.contains(parent))
        return static_cast<NodeInstanceMetaObject *>(parent);

    return new NodeInstanceMetaObject(nodeInstance, object, prefix, engine);
}

void NodeInstanceMetaObject::init(QObject *object, QQmlEngine *engine)
{
    //Creating QQmlOpenMetaObjectType
    m_type = new QQmlOpenMetaObjectType(metaObjectParent(), engine);
    m_type->addref();
    //Assigning type to this
    copyTypeMetaObject();

    //Assign this to object
    QObjectPrivate *op = QObjectPrivate::get(object);
    op->metaObject = this;

    //create cache
    cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this);
    cache->addref();

    //If our parent is not a VMEMetaObject we just se the flag to false again
    if (constructedMetaData(metaData))
        QQmlData::get(object)->hasVMEMetaObject = false;

    nodeInstanceMetaObjectList.insert(this, true);
    hasAssignedMetaObjectData = true;
}

NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstance::Pointer &nodeInstance, QQmlEngine *engine)
    : QQmlVMEMetaObject(nodeInstance->object(), cacheForObject(nodeInstance->object(), engine), vMEMetaDataForObject(nodeInstance->object())),
      m_nodeInstance(nodeInstance),
      m_context(engine->contextForObject(nodeInstance->object())),
      m_data(new MetaPropertyData),
      m_cache(0)
{
    init(nodeInstance->object(), engine);

    QQmlData *ddata = QQmlData::get(nodeInstance->object(), false);

    //Assign cache to object
    if (ddata && ddata->propertyCache) {
        ddata->propertyCache = m_cache;
    }
}

NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine)
    : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)),
      m_nodeInstance(nodeInstance),
      m_context(engine->contextForObject(object)),
      m_prefix(prefix),

      m_data(new MetaPropertyData),
      m_cache(0)
{
      init(object, engine);
}

NodeInstanceMetaObject::~NodeInstanceMetaObject()
{
    cache->release();
    m_type->release();

    nodeInstanceMetaObjectList.remove(this);
}

void NodeInstanceMetaObject::createNewProperty(const QString &name)
{
    int id = createProperty(name.toLatin1(), 0);
    setValue(id, QVariant());
    Q_ASSERT(id >= 0);
    Q_UNUSED(id);

    //Updating cache
    QQmlEnginePrivate::get(m_context->engine())->cache(this)->invalidate(m_context->engine(), this);

    QQmlProperty property(myObject(), name, m_context);
    Q_ASSERT(property.isValid());
}

int NodeInstanceMetaObject::createProperty(const char *name, const char *)
{
    int id =  m_type->createProperty(name);
    copyTypeMetaObject();
    return id;
}

void NodeInstanceMetaObject::setValue(int id, const QVariant &value)
{
    QPair<QVariant, bool> &prop = m_data->getDataRef(id);
    prop.first = propertyWriteValue(id, value);
    prop.second = true;
    QMetaObject::activate(myObject(), id + m_type->signalOffset(), 0);
}

QVariant NodeInstanceMetaObject::propertyWriteValue(int, const QVariant &value)
{
    return value;
}

int NodeInstanceMetaObject::openMetaCall(QMetaObject::Call call, int id, void **a)
{
    if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty)
            && id >= m_type->propertyOffset()) {
        int propId = id - m_type->propertyOffset();
        if (call == QMetaObject::ReadProperty) {
            //propertyRead(propId);
            *reinterpret_cast<QVariant *>(a[0]) = m_data->getData(propId);
        } else if (call == QMetaObject::WriteProperty) {
            if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast<QVariant *>(a[0]))  {
                //propertyWrite(propId);
                QPair<QVariant, bool> &prop = m_data->getDataRef(propId);
                prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
                prop.second = true;
                //propertyWritten(propId);
                activate(myObject(), m_type->signalOffset() + propId, 0);
            }
        }
        return -1;
    } else {
        QAbstractDynamicMetaObject *directParent = parent();
        if (directParent)
            return directParent->metaCall(call, id, a);
        else
            return myObject()->qt_metacall(call, id, a);
    }
}

int NodeInstanceMetaObject::metaCall(QMetaObject::Call call, int id, void **a)
{
    int metaCallReturnValue = -1;

    const QMetaProperty propertyById = QQmlVMEMetaObject::property(id);

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::QVariant
            && reinterpret_cast<QVariant *>(a[0])->type() == QVariant::Double
            && qIsNaN(reinterpret_cast<QVariant *>(a[0])->toDouble())) {
        return -1;
    }

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::Double
            && qIsNaN(*reinterpret_cast<double*>(a[0]))) {
        return -1;
    }

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::Float
            && qIsNaN(*reinterpret_cast<float*>(a[0]))) {
        return -1;
    }

    QVariant oldValue;

    if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal())
    {
        oldValue = propertyById.read(myObject());
    }

    ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef();

    QAbstractDynamicMetaObject *directParent = parent();
    if (directParent && id < directParent->propertyOffset()) {
        metaCallReturnValue = directParent->metaCall(call, id, a);
    } else {
        openMetaCall(call, id, a);
    }

    if ((call == QMetaObject::WriteProperty || call == QMetaObject::ReadProperty) && metaCallReturnValue < 0) {
        if (objectNodeInstance
                && objectNodeInstance->nodeInstanceServer()
                && objectNodeInstance->nodeInstanceServer()->dummyContextObject()
                && !(objectNodeInstance && !objectNodeInstance->isRootNodeInstance()
                     && property(id).name() == QLatin1String("parent"))) {

            QObject *contextDummyObject = objectNodeInstance->nodeInstanceServer()->dummyContextObject();
            int properyIndex = contextDummyObject->metaObject()->indexOfProperty(propertyById.name());
            if (properyIndex >= 0)
                metaCallReturnValue = contextDummyObject->qt_metacall(call, properyIndex, a);
        }
    }

    if (metaCallReturnValue >= 0
            && call == QMetaObject::WriteProperty
            && !propertyById.hasNotifySignal()
            && oldValue != propertyById.read(myObject()))
        notifyPropertyChange(id);

    return metaCallReturnValue;
}

void NodeInstanceMetaObject::notifyPropertyChange(int id)
{
    ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef();
    const QMetaProperty propertyById = property(id);

    if (objectNodeInstance && objectNodeInstance->nodeInstanceServer()) {
        if (id < propertyOffset()) {
            objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + propertyById.name());
        } else {
            objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + name(id - propertyOffset()));
        }
    }
}

int NodeInstanceMetaObject::count() const
{
    return m_type->propertyCount();
}

QByteArray NodeInstanceMetaObject::name(int idx) const
{
    return m_type->propertyName(idx);
}

void NodeInstanceMetaObject::copyTypeMetaObject()
{
    *static_cast<QMetaObject *>(this) = *m_type->metaObject();
}

} // namespace Internal
} // namespace QmlDesigner
<commit_msg>QmlDesigner.instances: fix for QmlPropertyCache<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "nodeinstancemetaobject.h"

#include "objectnodeinstance.h"
#include <QSharedPointer>
#include <QMetaProperty>
#include <qnumeric.h>
#include <QDebug>

#include <private/qqmlengine_p.h>
#include <private/qqmlpropertycache_p.h>

namespace QmlDesigner {
namespace Internal {

static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList;

struct MetaPropertyData {
    inline QPair<QVariant, bool> &getDataRef(int idx) {
        while (m_data.count() <= idx)
            m_data << QPair<QVariant, bool>(QVariant(), false);
        return m_data[idx];
    }

    inline QVariant &getData(int idx) {
        QPair<QVariant, bool> &prop = getDataRef(idx);
        if (!prop.second) {
            prop.first = QVariant();
            prop.second = true;
        }
        return prop.first;
    }

    inline bool hasData(int idx) const {
        if (idx >= m_data.count())
            return false;
        return m_data[idx].second;
    }

    inline int count() { return m_data.count(); }

    QList<QPair<QVariant, bool> > m_data;
};

static bool constructedMetaData(const QQmlVMEMetaData* data)
{
    return data->varPropertyCount == 0
            && data->propertyCount == 0
            && data->aliasCount == 0
            && data->signalCount == 0
            && data->methodCount == 0;
}

static QQmlVMEMetaData* fakeMetaData()
{
    QQmlVMEMetaData* data = new QQmlVMEMetaData;
    data->varPropertyCount = 0;
    data->propertyCount = 0;
    data->aliasCount = 0;
    data->signalCount = 0;
    data->methodCount = 0;

    return data;
}

static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object)
{
    QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
    if (metaObject)
        return metaObject->metaData;

    return fakeMetaData();
}

static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine)
{
    QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
    if (metaObject)
        return metaObject->cache;

    return QQmlEnginePrivate::get(engine)->cache(object);
}

static QAbstractDynamicMetaObject *abstractDynamicMetaObject(QObject *object)
{
    QObjectPrivate *op = QObjectPrivate::get(object);
    if (op->metaObject)
        return static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
    return const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(object->metaObject()));
}

NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine)
{
    //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject
    QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object());
    QDynamicMetaObjectData *parent = op->metaObject;
    if (nodeInstanceMetaObjectList.contains(parent))
        return static_cast<NodeInstanceMetaObject *>(parent);

    return new NodeInstanceMetaObject(nodeInstance, engine);
}

NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine)
{
    //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject
    QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object());
    QDynamicMetaObjectData *parent = op->metaObject;
    if (nodeInstanceMetaObjectList.contains(parent))
        return static_cast<NodeInstanceMetaObject *>(parent);

    return new NodeInstanceMetaObject(nodeInstance, object, prefix, engine);
}

void NodeInstanceMetaObject::init(QObject *object, QQmlEngine *engine)
{
    //Creating QQmlOpenMetaObjectType
    m_type = new QQmlOpenMetaObjectType(metaObjectParent(), engine);
    m_type->addref();
    //Assigning type to this
    copyTypeMetaObject();

    //Assign this to object
    QObjectPrivate *op = QObjectPrivate::get(object);
    op->metaObject = this;

    //create cache
    cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this);
    cache->addref();

    //If our parent is not a VMEMetaObject we just se the flag to false again
    if (constructedMetaData(metaData))
        QQmlData::get(object)->hasVMEMetaObject = false;

    nodeInstanceMetaObjectList.insert(this, true);
    hasAssignedMetaObjectData = true;
}

NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstance::Pointer &nodeInstance, QQmlEngine *engine)
    : QQmlVMEMetaObject(nodeInstance->object(), cacheForObject(nodeInstance->object(), engine), vMEMetaDataForObject(nodeInstance->object())),
      m_nodeInstance(nodeInstance),
      m_context(engine->contextForObject(nodeInstance->object())),
      m_data(new MetaPropertyData),
      m_cache(0)
{
    init(nodeInstance->object(), engine);

    QQmlData *ddata = QQmlData::get(nodeInstance->object(), false);

    //Assign cache to object
    if (ddata && ddata->propertyCache) {
        cache->setParent(ddata->propertyCache);
        cache->invalidate(engine, this);
        ddata->propertyCache = m_cache;
    }

}

NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine)
    : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)),
      m_nodeInstance(nodeInstance),
      m_context(engine->contextForObject(object)),
      m_prefix(prefix),

      m_data(new MetaPropertyData),
      m_cache(0)
{
      init(object, engine);
}

NodeInstanceMetaObject::~NodeInstanceMetaObject()
{
    cache->release();
    m_type->release();

    nodeInstanceMetaObjectList.remove(this);
}

void NodeInstanceMetaObject::createNewProperty(const QString &name)
{
    int id = createProperty(name.toLatin1(), 0);
    setValue(id, QVariant());
    Q_ASSERT(id >= 0);
    Q_UNUSED(id);

    //Updating cache
    QQmlPropertyCache *oldParent = m_cache->parent();
    QQmlEnginePrivate::get(m_context->engine())->cache(this)->invalidate(m_context->engine(), this);
    m_cache->setParent(oldParent);

    QQmlProperty property(myObject(), name, m_context);
    Q_ASSERT(property.isValid());
}

int NodeInstanceMetaObject::createProperty(const char *name, const char *)
{
    int id =  m_type->createProperty(name);
    copyTypeMetaObject();
    return id;
}

void NodeInstanceMetaObject::setValue(int id, const QVariant &value)
{
    QPair<QVariant, bool> &prop = m_data->getDataRef(id);
    prop.first = propertyWriteValue(id, value);
    prop.second = true;
    QMetaObject::activate(myObject(), id + m_type->signalOffset(), 0);
}

QVariant NodeInstanceMetaObject::propertyWriteValue(int, const QVariant &value)
{
    return value;
}

int NodeInstanceMetaObject::openMetaCall(QMetaObject::Call call, int id, void **a)
{
    if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty)
            && id >= m_type->propertyOffset()) {
        int propId = id - m_type->propertyOffset();
        if (call == QMetaObject::ReadProperty) {
            //propertyRead(propId);
            *reinterpret_cast<QVariant *>(a[0]) = m_data->getData(propId);
        } else if (call == QMetaObject::WriteProperty) {
            if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast<QVariant *>(a[0]))  {
                //propertyWrite(propId);
                QPair<QVariant, bool> &prop = m_data->getDataRef(propId);
                prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
                prop.second = true;
                //propertyWritten(propId);
                activate(myObject(), m_type->signalOffset() + propId, 0);
            }
        }
        return -1;
    } else {
        QAbstractDynamicMetaObject *directParent = parent();
        if (directParent)
            return directParent->metaCall(call, id, a);
        else
            return myObject()->qt_metacall(call, id, a);
    }
}

int NodeInstanceMetaObject::metaCall(QMetaObject::Call call, int id, void **a)
{
    int metaCallReturnValue = -1;

    const QMetaProperty propertyById = QQmlVMEMetaObject::property(id);

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::QVariant
            && reinterpret_cast<QVariant *>(a[0])->type() == QVariant::Double
            && qIsNaN(reinterpret_cast<QVariant *>(a[0])->toDouble())) {
        return -1;
    }

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::Double
            && qIsNaN(*reinterpret_cast<double*>(a[0]))) {
        return -1;
    }

    if (call == QMetaObject::WriteProperty
            && propertyById.userType() == QMetaType::Float
            && qIsNaN(*reinterpret_cast<float*>(a[0]))) {
        return -1;
    }

    QVariant oldValue;

    if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal())
    {
        oldValue = propertyById.read(myObject());
    }

    ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef();

    QAbstractDynamicMetaObject *directParent = parent();
    if (directParent && id < directParent->propertyOffset()) {
        metaCallReturnValue = directParent->metaCall(call, id, a);
    } else {
        openMetaCall(call, id, a);
    }

    if ((call == QMetaObject::WriteProperty || call == QMetaObject::ReadProperty) && metaCallReturnValue < 0) {
        if (objectNodeInstance
                && objectNodeInstance->nodeInstanceServer()
                && objectNodeInstance->nodeInstanceServer()->dummyContextObject()
                && !(objectNodeInstance && !objectNodeInstance->isRootNodeInstance()
                     && property(id).name() == QLatin1String("parent"))) {

            QObject *contextDummyObject = objectNodeInstance->nodeInstanceServer()->dummyContextObject();
            int properyIndex = contextDummyObject->metaObject()->indexOfProperty(propertyById.name());
            if (properyIndex >= 0)
                metaCallReturnValue = contextDummyObject->qt_metacall(call, properyIndex, a);
        }
    }

    if (metaCallReturnValue >= 0
            && call == QMetaObject::WriteProperty
            && !propertyById.hasNotifySignal()
            && oldValue != propertyById.read(myObject()))
        notifyPropertyChange(id);

    return metaCallReturnValue;
}

void NodeInstanceMetaObject::notifyPropertyChange(int id)
{
    ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef();
    const QMetaProperty propertyById = property(id);

    if (objectNodeInstance && objectNodeInstance->nodeInstanceServer()) {
        if (id < propertyOffset()) {
            objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + propertyById.name());
        } else {
            objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + name(id - propertyOffset()));
        }
    }
}

int NodeInstanceMetaObject::count() const
{
    return m_type->propertyCount();
}

QByteArray NodeInstanceMetaObject::name(int idx) const
{
    return m_type->propertyName(idx);
}

void NodeInstanceMetaObject::copyTypeMetaObject()
{
    *static_cast<QMetaObject *>(this) = *m_type->metaObject();
}

} // namespace Internal
} // namespace QmlDesigner
<|endoftext|>


<commit_before>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "service-settings-widget.h"
#include <AccountsUI/abstract-service-setup-context.h>
#include "settings-page.h"
#include "service-helper.h"
//MeegoTouch

#include <MContainer>
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MGridLayoutPolicy>
#include <MLabel>
#include <MButton>
#include <QDebug>
#include <QDomElement>
namespace AccountsUI {
class ServiceSettingsWidgetPrivate
{
public:
    ServiceSettingsWidgetPrivate()
            : enableServiceButton(0)
            , context(0)
            , containerMainPolicy(0)
            , showAllSettings(0)
            {}
    ~ServiceSettingsWidgetPrivate() {}
    MButton *enableServiceButton;
    AbstractServiceSetupContext *context;
    MGridLayoutPolicy *containerMainPolicy;
    bool showAllSettings;
};

ServiceSettingsWidget::ServiceSettingsWidget(AbstractServiceSetupContext *context,
                                             QGraphicsItem *parent,
                                             bool showOnlySettings,
                                             bool showAllSettings,
                                             bool enabled)
    : MContainer(parent),
    d_ptr(new ServiceSettingsWidgetPrivate())
{
    Q_D(ServiceSettingsWidget);
    d->context = context;
    d->showAllSettings = showAllSettings;
    MWidget *containerCentralWidget = new MWidget(this);
    MLayout *containerMainLayout = new MLayout(containerCentralWidget);
    d->containerMainPolicy = new MGridLayoutPolicy(containerMainLayout);
    if (!showOnlySettings) {
        MLabel *serviceNameLabel = new MLabel(this);
        d->enableServiceButton = new MButton(this);
        d->enableServiceButton->setViewType(MButton::switchType);
        d->enableServiceButton->setCheckable(true);
        if (context) {
            ServiceHelper *serviceHepler =
                new ServiceHelper(const_cast<Accounts::Service*>(context->service()), this);
            serviceNameLabel->setText(serviceHepler->prettyName());

            /*
             * no signals during widget creation
             * */
            d->context->enable(enabled);
            d->enableServiceButton->setChecked(enabled);
            connect(d->enableServiceButton, SIGNAL(toggled(bool)), this, SLOT(enabled(bool)));

            d->containerMainPolicy->addItem(serviceNameLabel, 0, 0, Qt::AlignLeft);
            d->containerMainPolicy->addItem(d->enableServiceButton, 0, 1, Qt::AlignRight);
            if (!serviceHepler->description().isNull()) {
                MLabel *descLabel = new MLabel(serviceHepler->description());
                d->containerMainPolicy->addItem(descLabel, 1, 0, Qt::AlignLeft);
            }
        }
    }
    if (context) {
        MWidget *widget = context->widget(0, showAllSettings);
        if (widget) {
            d->containerMainPolicy->addItem(widget, 2, 0);
        }
    }
    setCentralWidget(containerCentralWidget);
}

ServiceSettingsWidget::~ServiceSettingsWidget()
{
    delete d_ptr;
}

void ServiceSettingsWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void ServiceSettingsWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
    Q_D(ServiceSettingsWidget);
    if (d->context) {
        if (d->context->widget(0))
            openSettingsPage();
    }
}

void ServiceSettingsWidget::enabled(bool enabled)
{
    Q_D(ServiceSettingsWidget);
    if (!d->context)
        return;

    d->context->enable(enabled);

    if (enabled &&
        d->context->service()) {
            emit serviceButtonEnabled(d->context->service()->serviceType());
            qDebug() << Q_FUNC_INFO << __LINE__ << d->context->service()->serviceType() << enabled;
    }
}

void ServiceSettingsWidget::setServiceButtonEnable(bool enable)
{
    Q_D(ServiceSettingsWidget);
    qDebug() << Q_FUNC_INFO << __LINE__;

    if (d->enableServiceButton->isChecked() != enable)
        d->enableServiceButton->setChecked(enable);
}

void ServiceSettingsWidget::openSettingsPage()
{
    Q_D(ServiceSettingsWidget);
    SettingsPage *settingsPage =
            new SettingsPage(d->context);
    settingsPage->appear();
}

}//end of namespace
<commit_msg>fixing bug: 198688 having logical id in the names<commit_after>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "service-settings-widget.h"
#include <AccountsUI/abstract-service-setup-context.h>
#include "settings-page.h"
#include "service-helper.h"
//MeegoTouch

#include <MContainer>
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MGridLayoutPolicy>
#include <MLabel>
#include <MButton>
#include <MLocale>
#include <QDebug>
#include <QDomElement>
namespace AccountsUI {
class ServiceSettingsWidgetPrivate
{
public:
    ServiceSettingsWidgetPrivate()
            : enableServiceButton(0)
            , context(0)
            , containerMainPolicy(0)
            , showAllSettings(0)
            {}
    ~ServiceSettingsWidgetPrivate() {}
    MButton *enableServiceButton;
    AbstractServiceSetupContext *context;
    MGridLayoutPolicy *containerMainPolicy;
    bool showAllSettings;
};

ServiceSettingsWidget::ServiceSettingsWidget(AbstractServiceSetupContext *context,
                                             QGraphicsItem *parent,
                                             bool showOnlySettings,
                                             bool showAllSettings,
                                             bool enabled)
    : MContainer(parent),
    d_ptr(new ServiceSettingsWidgetPrivate())
{
    Q_D(ServiceSettingsWidget);
    d->context = context;
    d->showAllSettings = showAllSettings;
    QString catalog = d->context->service()->trCatalog();
    if (!catalog.isEmpty()) {
         MLocale locale;
         locale.installTrCatalog(catalog);
         MLocale::setDefault(locale);
    }
    MWidget *containerCentralWidget = new MWidget(this);
    MLayout *containerMainLayout = new MLayout(containerCentralWidget);
    d->containerMainPolicy = new MGridLayoutPolicy(containerMainLayout);
    if (!showOnlySettings) {
        MLabel *serviceNameLabel = new MLabel(this);
        d->enableServiceButton = new MButton(this);
        d->enableServiceButton->setViewType(MButton::switchType);
        d->enableServiceButton->setCheckable(true);
        if (context) {
            ServiceHelper *serviceHepler =
                new ServiceHelper(const_cast<Accounts::Service*>(context->service()), this);
            serviceNameLabel->setText(serviceHepler->prettyName());

            /*
             * no signals during widget creation
             * */
            d->context->enable(enabled);
            d->enableServiceButton->setChecked(enabled);
            connect(d->enableServiceButton, SIGNAL(toggled(bool)), this, SLOT(enabled(bool)));

            d->containerMainPolicy->addItem(serviceNameLabel, 0, 0, Qt::AlignLeft);
            d->containerMainPolicy->addItem(d->enableServiceButton, 0, 1, Qt::AlignRight);
            if (!serviceHepler->description().isNull()) {
                MLabel *descLabel = new MLabel(serviceHepler->description());
                d->containerMainPolicy->addItem(descLabel, 1, 0, Qt::AlignLeft);
            }
        }
    }
    if (context) {
        MWidget *widget = context->widget(0, showAllSettings);
        if (widget) {
            d->containerMainPolicy->addItem(widget, 2, 0);
        }
    }
    setCentralWidget(containerCentralWidget);
}

ServiceSettingsWidget::~ServiceSettingsWidget()
{
    delete d_ptr;
}

void ServiceSettingsWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void ServiceSettingsWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
    Q_D(ServiceSettingsWidget);
    if (d->context) {
        if (d->context->widget(0))
            openSettingsPage();
    }
}

void ServiceSettingsWidget::enabled(bool enabled)
{
    Q_D(ServiceSettingsWidget);
    if (!d->context)
        return;

    d->context->enable(enabled);

    if (enabled &&
        d->context->service()) {
            emit serviceButtonEnabled(d->context->service()->serviceType());
            qDebug() << Q_FUNC_INFO << __LINE__ << d->context->service()->serviceType() << enabled;
    }
}

void ServiceSettingsWidget::setServiceButtonEnable(bool enable)
{
    Q_D(ServiceSettingsWidget);
    qDebug() << Q_FUNC_INFO << __LINE__;

    if (d->enableServiceButton->isChecked() != enable)
        d->enableServiceButton->setChecked(enable);
}

void ServiceSettingsWidget::openSettingsPage()
{
    Q_D(ServiceSettingsWidget);
    SettingsPage *settingsPage =
            new SettingsPage(d->context);
    settingsPage->appear();
}

}//end of namespace
<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<string>)
#include <string>
#endif

#if __has_include(<QString>)
#include <QString>
#endif

#include <ox/std/bstring.hpp>
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>

namespace ox::detail {

constexpr const char *stringify(const char *s) noexcept {
	return s;
}

template<std::size_t size>
constexpr const char *stringify(const ox::BString<size> &s) noexcept {
    return s.c_str();
}

constexpr const char *stringify(const ox::String &s) noexcept {
	return s.c_str();
}

#if __has_include(<string>)
constexpr const char *stringify(const std::string &s) noexcept {
	return s.c_str();
}
#endif

#if __has_include(<QString>)
constexpr const char *stringify(const QString &s) noexcept {
	return s.c_str();
}
#endif

class FmtArg {

	private:
		char dataStr[10] = {};

	public:
		const char *out = nullptr;

		template<typename T>
		constexpr FmtArg(T v) noexcept {
			if constexpr(is_bool_v<T>) {
				out = v ? "true" : "false";
			} else if constexpr(is_integral_v<T>) {
				out = ox_itoa(v, dataStr);
			} else {
				out = stringify(v);
			}
		}

};

[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
	uint64_t cnt = 0;
	const auto prev = [str](std::size_t i) -> char {
		if (i > 0) {
			return str[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [str](std::size_t i) -> char {
		if (i < ox_strlen(str) - 1) {
			return str[i + 1];
		} else {
			return '\0';
		}
	};
	for (std::size_t i = 0; i < ox_strlen(str); ++i) {
		if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++cnt;
		}
	}
	return cnt;
}

static_assert(argCount("sadf asdf") == 0);
static_assert(argCount("{}") == 1);
static_assert(argCount("{}{}") == 2);
static_assert(argCount("thing1: {}, thing2: {}") == 2);
static_assert(argCount("thing1: {}, thing2: {}{}") == 3);

struct FmtSegment {
	const char *str = nullptr;
	unsigned length = 0;

	constexpr bool operator==(const FmtSegment &o) const noexcept {
		return length == o.length && ox_strncmp(str, o.str, length) == 0;
	}

	constexpr bool operator!=(const FmtSegment &o) const noexcept {
		return length != o.length || ox_strncmp(str, o.str, length) != 0;
	}
};

template<std::size_t sz>
struct Fmt {
	static constexpr std::size_t size = sz;
	FmtSegment segments[sz];

	constexpr bool operator==(const Fmt<sz> &o) const noexcept {
		for (std::size_t i = 0; i < sz; ++i) {
			if (segments[i] != o.segments[i]) {
				return false;
			}
		}
		return true;
	}
};

template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
	Fmt<segementCnt> out;
	const auto prev = [fmt](std::size_t i) -> char {
		if (i > 0) {
			return fmt[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [fmt](std::size_t i) -> char {
		if (i < ox_strlen(fmt) - 1) {
			return fmt[i + 1];
		} else {
			return '\0';
		}
	};
	auto current = &out.segments[0];
	current->str = fmt;
	for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
		if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++current;
			current->str = fmt + i + 2;
			current->length = 0;
			i += 1;
		} else {
			++current->length;
		}
	}
	return out;
}

static_assert([] {
		constexpr auto fmt = "{}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
			{
				{"", 0},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
			{
				{"thing: ", 7},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}, thing2: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
			{
				{"thing: ", 7},
				{", thing2: ", 10},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}, thing2: {}s";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
			{
				{"thing: ", 7},
				{", thing2: ", 10},
				{"s", 1},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "loadTexture: section: {}, w: {}, h: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<4>{
			{
				{"loadTexture: section: ", 22},
				{", w: ", 5},
				{", h: ", 5},
			}
		};
	}()
);

}
<commit_msg>[ox/std] Make fmt stringify(std::string) require C++20 and remove QString variant<commit_after>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<string>)
#include <string>
#endif

#if __has_include(<QString>)
#include <QString>
#endif

#include <ox/std/bstring.hpp>
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>

namespace ox::detail {

constexpr const char *stringify(const char *s) noexcept {
	return s;
}

template<std::size_t size>
constexpr const char *stringify(const ox::BString<size> &s) noexcept {
    return s.c_str();
}

constexpr const char *stringify(const ox::String &s) noexcept {
	return s.c_str();
}

#if __has_include(<string>) && __cplusplus >= 202002L
constexpr const char *stringify(const std::string &s) noexcept {
	return s.c_str();
}
#endif

class FmtArg {

	private:
		char dataStr[10] = {};

	public:
		const char *out = nullptr;

		template<typename T>
		constexpr FmtArg(T v) noexcept {
			if constexpr(is_bool_v<T>) {
				out = v ? "true" : "false";
			} else if constexpr(is_integral_v<T>) {
				out = ox_itoa(v, dataStr);
			} else {
				out = stringify(v);
			}
		}

};

[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
	uint64_t cnt = 0;
	const auto prev = [str](std::size_t i) -> char {
		if (i > 0) {
			return str[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [str](std::size_t i) -> char {
		if (i < ox_strlen(str) - 1) {
			return str[i + 1];
		} else {
			return '\0';
		}
	};
	for (std::size_t i = 0; i < ox_strlen(str); ++i) {
		if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++cnt;
		}
	}
	return cnt;
}

static_assert(argCount("sadf asdf") == 0);
static_assert(argCount("{}") == 1);
static_assert(argCount("{}{}") == 2);
static_assert(argCount("thing1: {}, thing2: {}") == 2);
static_assert(argCount("thing1: {}, thing2: {}{}") == 3);

struct FmtSegment {
	const char *str = nullptr;
	unsigned length = 0;

	constexpr bool operator==(const FmtSegment &o) const noexcept {
		return length == o.length && ox_strncmp(str, o.str, length) == 0;
	}

	constexpr bool operator!=(const FmtSegment &o) const noexcept {
		return length != o.length || ox_strncmp(str, o.str, length) != 0;
	}
};

template<std::size_t sz>
struct Fmt {
	static constexpr std::size_t size = sz;
	FmtSegment segments[sz];

	constexpr bool operator==(const Fmt<sz> &o) const noexcept {
		for (std::size_t i = 0; i < sz; ++i) {
			if (segments[i] != o.segments[i]) {
				return false;
			}
		}
		return true;
	}
};

template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
	Fmt<segementCnt> out;
	const auto prev = [fmt](std::size_t i) -> char {
		if (i > 0) {
			return fmt[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [fmt](std::size_t i) -> char {
		if (i < ox_strlen(fmt) - 1) {
			return fmt[i + 1];
		} else {
			return '\0';
		}
	};
	auto current = &out.segments[0];
	current->str = fmt;
	for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
		if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++current;
			current->str = fmt + i + 2;
			current->length = 0;
			i += 1;
		} else {
			++current->length;
		}
	}
	return out;
}

static_assert([] {
		constexpr auto fmt = "{}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
			{
				{"", 0},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
			{
				{"thing: ", 7},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}, thing2: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
			{
				{"thing: ", 7},
				{", thing2: ", 10},
				{"", 0},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "thing: {}, thing2: {}s";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
			{
				{"thing: ", 7},
				{", thing2: ", 10},
				{"s", 1},
			}
		};
	}()
);
static_assert([] {
		constexpr auto fmt = "loadTexture: section: {}, w: {}, h: {}";
		return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<4>{
			{
				{"loadTexture: section: ", 22},
				{", w: ", 5},
				{", h: ", 5},
			}
		};
	}()
);

}
<|endoftext|>